Counting the total number of rows depending on a column value - oracle

I have a query that should count the total number of rows returned depending on a column value. For example:
As you can see, the M field should display the total number of rows returned which should be 5 because the FT_LOT are all the same value. Here is the query that I have so far:
SELECT DISTINCT
VBATCH_ID, MAXIM_PN, BAGNUMBER, FT_LOT
, m
, level as n
FROM
(
SELECT
VBATCH_ID, MAXIM_PN, BAGNUMBER, FT_LOT, QTY, DC, PRINTDATE, WS_GREEN, WS_PNR, WS_PCN, MSL, BAKETIME, EXPTIME
, una
, dulo
, (dulo - una) + 1 AS m
FROM
(
SELECT c.containername VBATCH_ID
,pb.productname MAXIM_PN
,bn.wipdatavalue BAGNUMBER
,ln.wipdatavalue FT_LOT
,aw.wipdatavalue QTY
,DECODE(ln.wipdatavalue,la.attr_081,la.attr_083
,la.attr_085,la.attr_087
,la.attr_089,la.attr_091
,la.attr_093,la.attr_095
,la.attr_097,la.attr_099
,la.attr_101,la.attr_103
,la.attr_105,la.attr_107
,la.attr_109,la.attr_111
,la.attr_113,la.attr_116
,la.attr_117,la.attr_119
) DC
,TO_CHAR(SYSDATE,'MM/DD/YYYY HH:MI:SS PM') PRINTDATE
,DECODE(UPPER(la.attr_158),'GREEN','HF',NULL) WS_GREEN
,DECODE(la.attr_140,NULL,NULL,'PNR') WS_PNR
,DECODE(la.Attr_080,NULL,NULL,'PCN') WS_PCN
,p.attr_011 MSL
,P.attr_013 BAKETIME
,p.attr_014 EXPTIME
, CASE
WHEN INSTR(bn.wipdatavalue, '-') = 0 THEN
bn.wipdatavalue
ELSE
SUBSTR(bn.wipdatavalue, 1, INSTR(bn.wipdatavalue, '-')-1)
END AS una
, CASE
WHEN INSTR(bn.wipdatavalue, '-') = 0 THEN
bn.wipdatavalue
ELSE
SUBSTR(bn.wipdatavalue, INSTR(bn.wipdatavalue, '-') + 1)
END AS dulo
FROM Container C
JOIN a_lotattributes la ON c.lotattributesid = la.lotattributesid
JOIN product p ON c.productid=p.productid
JOIN productbase pb ON p.productbaseid=pb.productbaseid
JOIN a_adhocwipdatarecord a ON a.objectrefid=c.containerid
JOIN a_adhocwipdatarecorddetails bn ON a.adhocwipdatarecordid=bn.adhocwipdatarecordid AND bn.wipdatanamename ='TR_BAG_NUMBER'
LEFT JOIN a_adhocwipdatarecorddetails ln ON a.adhocwipdatarecordid=ln.adhocwipdatarecordid AND ln.wipdatanamename ='TR_FT_LOT NUMBER'
LEFT JOIN a_adhocwipdatarecorddetails aw ON A.adhocwipdatarecordid=aw.adhocwipdatarecordid AND aw.wipdatanamename ='TR_FT LOT QTY'
WHERE ln.wipdatavalue = :ftlot AND bn.wipdatavalue LIKE :wip
)
) WHERE level LIKE :n
CONNECT BY LEVEL <= m
ORDER BY BAGNUMBER
Thanks for helping out guys.

Actually GROUP BY is not the solution. Having looked again at your desired output I have realised that what you want is an analytic count.
Your posted query is a bit of a mess and, sorry ,but I'm not prepared to invest time in it. This is the sort of structure you need:
select vbatch_id, maxim_pn, bagnumber, ft_lot
, count(*) over (partition by ft_lot) m
from whatever ...
Find out more.
Not sure why you need the DISTINCT. DISTINCT almost always indicates a failure to get the WHERE clause right.

Related

running balance debit credit column in oracle query

Output result
I want the running balance in my query. I had wrote the query.
May be i am mistaking any where please let me know.
SELECT
ACC_VMAST.VM_DATE,
ACC_VDET.CHEQUE,
ACC_VMAST.NARRATION,
ACC_VDET.DEBIT,
ACC_VDET.CREDIT,
sum(nvl(ACC_VDET.DEBIT,0) - nvl(ACC_VDET.CREDIT,0) )
over (order by ACC_VMAST.VM_DATE , ACC_VDET.DEBIT ) running_bal
FROM ACC_VMAST,
ACC_VDET,
ACC_COA
WHERE ACC_VMAST.VM_PK=ACC_VDET.VM_PK
AND ACC_COA.COA_PK=ACC_VDET.COA_PK
AND ACC_VMAST.POST_BY IS NOT NULL
AND ACC_VMAST.CANCEL_STATUS IS NULL
AND ACC_VMAST.VM_DATE BETWEEN '07/06/2021' AND '07/07/2021'
AND ACC_VDET.COA_PK= '303'
ORDER BY ACC_VMAST.VM_DATE , ACC_VDET.DEBIT;
If you have rows that have the same values for the ORDER BY clause then when you SUM the values then all the rows with the same ORDER BY value will be grouped together and totalled.
To prevent that, you can add the ROWNUM pseudo-column to the ORDER BY clause of the analytic function so that there will not be any ties:
SELECT m.VM_DATE,
d.CHEQUE,
m.NARRATION,
d.DEBIT,
d.CREDIT,
SUM( COALESCE(d.DEBIT,0) - COALESCE(d.CREDIT,0) )
OVER ( ORDER BY m.VM_DATE, d.DEBIT, ROWNUM ) AS running_bal
FROM ACC_VMAST m
INNER JOIN ACC_VDET d
ON (m.VM_PK = d.VM_PK)
INNER JOIN ACC_COA c
ON (c.COA_PK = d.COA_PK)
WHERE m.POST_BY IS NOT NULL
AND m.CANCEL_STATUS IS NULL
AND m.VM_DATE BETWEEN DATE '2021-07-06' AND DATE '2021-07-07'
AND d.COA_PK = '303'
ORDER BY
m.VM_DATE,
d.DEBIT;
You need to add a row range with "rows between unbounded preceding and current row".
sum(nvl(ACC_VDET.DEBIT,0) - nvl(ACC_VDET.CREDIT,0) )
over (order by ACC_VMAST.VM_DATE , ACC_VDET.DEBIT rows between unbounded preceding and current row ) running_bal

Left Join with Multiple Conditions and MAX Value

I'm trying to execute a left join where multiple conditions must be met with the inclusion of pulling in the MAX sequence number that meets those conditions.
The left join is on the unique identifier in both tables. Table acaps_history has several rows for each app_id. I need to pull in only one row with the highest seq_number and activity_code of 'XU'. If the code 'XU' doesn't exist for the given app_id, then the case statement above should return 'N' for that row. The code I have currently just isn't working - returning the error "a column may not be outer-joined to a subquery":
create table orig_play3 as
(select
x.*,
case when xa.activity_code in 'XU' then 'Y' else 'N' end as cpo_flag
from
dfs_tab_orig_play_x x
left join cf.acaps_history xa on
x.APP_ID = xa.FOC_APPL_ID
and xa.activity_code in 'XU'
and xa.seq_number = (select max(seq_number) from cf.acaps_history where FOC_APPL_ID=x.app_id)
)
Given your error, it seems that the issue is the last part of your query:
and xa.seq_number = (select max(seq_number) from cf.acaps_history where FOC_APPL_ID=x.app_id)
This is still operating in the context of the ON clause, so the sub-query to find the max sequence number is the issue.
You should be able to avoid this by moving that sub-query out of the ON clause:
LEFT JOIN (
SELECT FOC_APPL_ID, activity_code, seq_number
FROM cf.acaps_history
WHERE activity_code in 'XU'
) xa
ON x.APP_ID = xa.FOC_APPL_ID
WHERE xa.seq_number = (select max(ah.seq_number) from cf.acaps_history ah where ah.FOC_APPL_ID=x.app_id and ah.activity_code in 'XU')
This may be the most inefficient way to execute this query, but it worked... It took like 3 minutes to run (table size is over 600K rows), but again, it returned the results I needed:
create table test as (
select x.*,
case when xb.activity_code in 'XU' then 'Y' else 'N' end as cpo_flag
from dfs_tab_orig_play_x x
left join
(select
xa.FOC_APPL_ID, xa.activity_code, xa.seq_number
from dfs_tab_orig_play_x x, cf.acaps_history xa
where x.app_id = xa.FOC_APPL_ID (+)
and xa.seq_number = (select max(seq_number) from cf.acaps_history where
x.app_id=FOC_APPL_ID(+) and activity_code in 'XU')) xb
on x.app_id = xb.FOC_APPL_ID (+)
)
If you are on 12c, I like OUTER APPLY for this sort of thing, because it lets you sort the rows for each app_id descending by seq_number and then just pick the highest one.
SELECT
x.*,
CASE
WHEN xa.activity_code IN 'XU' THEN 'Y'
ELSE 'N'
END
AS cpo_flag
FROM
dfs_tab_orig_play_x x
OUTER APPLY ( SELECT *
FROM cf.acaps_history xa
WHERE xa.foc_appl_id = x.app_id
AND xa.activity_code = 'XU'
ORDER BY xa.seq_number DESC
FETCH FIRST 1 ROW ONLY ) xa
Note: this logic is a little different from what you posted. In this version, it will join to the acaps_history row having the highest seq_number from among 'XU' records for the given app_id. Your version was joining to the row having the highest seq_number for the given app_id, whether that row was an 'XU' row or not. I am assuming (with little reason) that that was a bug on your part. But, if it wasn't, my version won't work as given.

CTX index in oracle is quite slow?

I am using CTX index in oracle column .
I have two table
xyz have 6 million record.
abc has 100k record
What i want to achieve is this.
Scenario - I have to union them and then i need the data in order by of date . And then i need pagination record on them.
select page_loc, blurb_id, article_id, hit_date,val_rank from (
SELECT REGEXP_REPLACE(regexp_replace(page_loc, '^.*mercer\.com'),'\?.*$') AS page_loc,
blurb_id, article_id, hit_date,RANK() OVER (ORDER BY hit_date DESC) AS val_rank
from (
SELECT page_loc, blurb_id, article_id, hit_date
FROM abc u INNER JOIN person p ON u.person_id=p.person_id
WHERE (CONTAINS(u.page_loc,v_pattern) > 0 )
UNION ALL
SELECT e page_loc, blurb_id, article_id, hit_date
FROM xyz u INNER JOIN person p ON u.person_id=p.person_id
WHERE ( CONTAINS(u.page_loc,v_pattern) > 0)
) p
left join
company c on c.company_id = p.company_id
) a
where val_rank between (v_page_no -1) * 10 and v_page_no * 10
v_pattern --> searching text
v_page_no --> page count
It take long time when i have record for some v_pattern more e.g 100k,
for example a word have 2 million record. it take more than 20 min.
Any idea what can i do . or it is not possible with oracle.
NOTE :- when i analysis it i found order by and pagination making it slow . How can i overcome that

How to Delete these Records in Netezza(Aginity)

I Written a Query to Identify the Duplicate records.
As Below.
WITH DUPS AS
(SELECT A_SURVEYID,
CAST(e_responsedate AS DATE) AS e_responsedate,
E_LG_VM_SURVEY_TYPE_ENUM
FROM TRANSIENT..INTERIM_NPS_SURVEY_MOBILE_RESULTS_20170909 a
GROUP BY A_SURVEYID,
CAST(e_responsedate AS DATE),
E_LG_VM_SURVEY_TYPE_ENUM
HAVING COUNT(*) > 1
),
RANKED AS
(SELECT R.DRS_RECORD_ID,
R.A_SURVEYID,
R.e_responsedate ,
ROW_NUMBER() OVER ( PARTITION BY R.A_SURVEYID, CAST(R.e_responsedate AS DATE),
R.E_LG_VM_SURVEY_TYPE_ENUM ORDER BY SUBSTR(R.DRS_RECORD_ID, INSTR(':', R.DRS_RECORD_ID, 37) + 1, 14) DESC,
SUBSTR(R.DRS_RECORD_ID, INSTR(':', R.DRS_RECORD_ID, 32) + 1, 4) ASC ) AS DR
FROM TRANSIENT..INTERIM_NPS_SURVEY_MOBILE_RESULTS_20170909 R
INNER JOIN DUPS
ON R.A_SURVEYID = DUPS.A_SURVEYID
AND CAST(R.e_responsedate AS DATE) = DUPS.e_responsedate
AND R.E_LG_VM_SURVEY_TYPE_ENUM = DUPS.E_LG_VM_SURVEY_TYPE_ENUM
)
SELECT *
FROM TRANSIENT..INTERIM_NPS_SURVEY_MOBILE_RESULTS_20170909 F
INNER JOIN RANKED
ON F.DRS_RECORD_ID = RANKED.DRS_RECORD_ID
WHERE RANKED.DR > 1
--
By Using the Above Query am able to retrieve the records.(some 6000+ ).
But am unable to delete those records.
Can you please help me on this.
Regards,
Krish
You are very close. In the last 5 lines, do this instead:
Delete from FROM TRANSIENT..INTERIM_NPS_SURVEY_MOBILE_RESULTS_2017090
Where DRS_RECORD_ID in (
Select DRS_RECORD_ID from RANKED WHERE DR>1)
Should work :)
BTW: I'm pretty sure this can be done with less code, but that is not important...

oracle procedure cursor query when case statement

CURSOR BULKUPDATE IS
SELECT SUM(B.ACCOUNT_BALANCE) AS ACCOUNT_BALANCE,C.CIF AS CIF_ID FROM _ACCOUNTS_STAGING2 B JOIN _RELATION_STAGING2 C
ON B.ACCOUNT_IDENTIFICATION_NUMBER = C.ACCOUNT_IDENTIFICATION_NUMBER AND B.SOURCEID=C.SOURCEID JOIN _CUSTOMER_STAGING2 A ON A.CIF=C.CIF AND A.SOURCEID=C.SOURCEID WHERE C.ROLE_ON_ACCOUNT IN
(Select Rollonaccount From _Roleaccount_Master Where Aggregatebalance='Y')
And upper(B.Scheme_Type) In (Select Scheme_Type From _Schema_Type_Master Where
Depository_Account = 'Y') Group By C.Cif;
Rec_Bulkupdate Bulkupdate%Rowtype;
I am using this query to sum account balances based on different cif and source. The question is I want to calculate four different types of sum on the basis of _Schema_Type_Master. For example I want to check now current_account='Y' instead of Depository_Account='Y'
_ACCOUNTS_STAGING2 B JOIN _RELATION_STAGING2 C
ON B.ACCOUNT_IDENTIFICATION_NUMBER = C.ACCOUNT_IDENTIFICATION_NUMBER AND B.SOURCEID=C.SOURCEID JOIN _CUSTOMER_STAGING2 A ON A.CIF=C.CIF AND A.SOURCEID=C.SOURCEID WHERE C.ROLE_ON_ACCOUNT IN
(Select Rollonaccount From _Roleaccount_Master Where Aggregatebalance='Y')
And upper(B.Scheme_Type) In (Select Scheme_Type From _Schema_Type_Master Where
current_account='Y') Group By C.Cif;
Rec_Bulkupdate Bulkupdate%Rowtype;
Is there any way or do I need to write four different cursors for that??
You can remove dipository_account='Y' and current_account='Y' and use case in select as -
SELECT SUM(CASE WHEN Depository_Account = 'Y' THEN B.ACCOUNT_BALANCE ELSE 0 END) AS DIPOSITORY_ACCOUNT_BALANCE,
SUM(CASE WHEN current_account = 'Y' THEN B.ACCOUNT_BALANCE ELSE 0 END) AS CURRENT_ACCOUNT_BALANCE
and then rest of your code. You will get two different columns for sum of Depository account and Current account.
And if filter for dipository_account='Y' and current_account='Y' is required, then use them in where condition with or operator :
AND (dipository_account='Y' or current_account='Y')

Resources