SQL Query is taking to long to excecute - sql

I have the below query that is taking too long:
{SELECT /*+ PARALLEL(5) */
EXTER.ACE_IT_REGION_ID ,
EXTER.ACE_IT_LOCATION_CODE,
EXTER.ACE_IT_ORD_NUM,
EXTER.TOTAL_ITEM_PRICE_PER_ORDER,
EXTER.TOTAL_ACE_PAYD_AMOUNT,
EXTER.ACE_ORD_COMPLETION_TIME AS DATEOFDATA
FROM
(SELECT /*+ use_hash(TAB1,TAB2) +*/
DISTINCT
TAB1.ACE_IT_REGION_ID ,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM,
TAB1.TOTAL_ITEM_PRICE_PER_ORDER,
TAB2.TOTAL_ACE_PAYD_AMOUNT,
TAB1.ACE_ORD_COMPLETION_TIME
FROM
(SELECT AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.SUM_PRICE_PLUS_TAX,
AAA.TOTAL_DISCOUNT,
(AAA.SUM_PRICE_PLUS_TAX-AAA.TOTAL_DISCOUNT) AS TOTAL_ITEM_PRICE_PER_ORDER,
TRUNC(AAA.ACE_ORD_COMPLETION_TIME)
FROM (SELECT B.ACE_IT_REGION_ID AS ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE AS ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM AS ACE_IT_ORD_NUM,
(SUM(B.ACE_IT_ITEM_PRICE + B.ACE_IT_TAX_AMT)*B.ACE_IT_QTY) AS SUM_PRICE_PLUS_TAX,
SUM(B.ACE_IT_DISC_AMT+B.ACE_IT_AUTO_DISC_AMT) AS TOTAL_DISCOUNT,
TRUNC(A.ACE_ORD_COMPLETION_TIME ) AS ACE_ORD_COMPLETION_TIME
FROM POSDB.ACE_ORDERS A, POSDB.ACE_ITEM_TRAN B
WHERE A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
AND A.ACE_ORD_REGION_ID = B.ACE_IT_REGION_ID
AND A.ACE_ORD_LOCATION_CODE = B.ACE_IT_LOCATION_CODE
AND A.ACE_ORD_NUM = B.ACE_IT_ORD_NUM
AND A.ACE_ORD_TYPE = 'IS'
AND (A.ACE_ORD_STATUS = 'CR'
OR A.ACE_ORD_STATUS IS NULL
OR A.ACE_ORD_STATUS LIKE ' %'
OR A.ACE_ORD_STATUS LIKE '% ')
AND (B.ACE_IT_VOID_IND <> 'V' OR B.ACE_IT_VOID_IND IS NULL )
GROUP BY B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
A.ACE_ORD_COMPLETION_TIME) AAA
ORDER BY AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.ACE_ORD_COMPLETION_TIME) TAB1,
(SELECT ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM,
SUM(ACE_PAYD_AMOUNT) TOTAL_ACE_PAYD_AMOUNT
FROM POSDB.ACE_PAYMENT_DTL
WHERE ACE_PAYD_POSTING_TIMESTAMP BETWEEN TRUNC(SYSDATE-1) AND TRUNC(SYSDATE)
AND (ACE_PAYD_STATUS <> 'V' OR ACE_PAYD_STATUS IS NULL )
GROUP BY
ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM) TAB2
WHERE TAB1.ACE_IT_REGION_ID = TAB2.ACE_PAYD_REGION_ID
AND TAB1.ACE_IT_LOCATION_CODE = TAB2.ACE_PAYD_LOCATION_CODE
AND TAB1.ACE_IT_ORD_NUM = TAB2.ACE_PAYD_ORD_NUM
ORDER BY
TAB1.ACE_IT_REGION_ID ,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM ) EXTER
WHERE (EXTER.TOTAL_ITEM_PRICE_PER_ORDER = EXTER.TOTAL_ACE_PAYD_AMOUNT)
AND EXTER.ACE_ORD_COMPLETION_TIME IS NOT NULL;}
Please give me any suggestions. I have used hints but still not sure why it's taking so much time.
All the tables are huge, about 300,000,000 each.
Before joining the table in tab3 temp table it was taking 5 mins...but now even after 20-25 min it does not return records.

slightly cleaned-up for readability of each being subset of next level down. Also removed the redundant outer query and just added it's WHERE clause to the one inside. Should be same result
SELECT DISTINCT *
FROM
( SELECT
AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.SUM_PRICE_PLUS_TAX,
AAA.TOTAL_DISCOUNT,
AAA.SUM_PRICE_PLUS_TAX - AAA.TOTAL_DISCOUNT AS TOTAL_ITEM_PRICE_PER_ORDER,
TRUNC(AAA.ACE_ORD_COMPLETION_TIME) AS DATEOFDATA
FROM
( SELECT
B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
( SUM( B.ACE_IT_ITEM_PRICE + B.ACE_IT_TAX_AMT)
* B.ACE_IT_QTY ) AS SUM_PRICE_PLUS_TAX,
SUM( B.ACE_IT_DISC_AMT + B.ACE_IT_AUTO_DISC_AMT) AS TOTAL_DISCOUNT,
TRUNC( A.ACE_ORD_COMPLETION_TIME ) AS ACE_ORD_COMPLETION_TIME
FROM
POSDB.ACE_ORDERS A,
POSDB.ACE_ITEM_TRAN B
WHERE
A.ACE_ORD_TYPE = 'IS'
AND A.ACE_ORD_REGION_ID = B.ACE_IT_REGION_ID
AND A.ACE_ORD_LOCATION_CODE = B.ACE_IT_LOCATION_CODE
AND A.ACE_ORD_NUM = B.ACE_IT_ORD_NUM
AND A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
AND ( A.ACE_ORD_STATUS = 'CR'
OR A.ACE_ORD_STATUS IS NULL
OR A.ACE_ORD_STATUS LIKE ' %'
OR A.ACE_ORD_STATUS LIKE '% ')
AND ( B.ACE_IT_VOID_IND <> 'V'
OR B.ACE_IT_VOID_IND IS NULL )
GROUP BY
B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
A.ACE_ORD_COMPLETION_TIME ) AAA
ORDER BY
AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.ACE_ORD_COMPLETION_TIME) TAB1,
( SELECT
APD.ACE_PAYD_REGION_ID,
APD.ACE_PAYD_LOCATION_CODE,
APD.ACE_PAYD_ORD_NUM,
SUM(APD.ACE_PAYD_AMOUNT) TOTAL_ACE_PAYD_AMOUNT
FROM
POSDB.ACE_PAYMENT_DTL APD
WHERE
APD.ACE_PAYD_POSTING_TIMESTAMP
BETWEEN TRUNC(SYSDATE-1) AND TRUNC(SYSDATE)
AND ( APD.ACE_PAYD_STATUS <> 'V'
OR APD.ACE_PAYD_STATUS IS NULL )
GROUP BY
APD.ACE_PAYD_REGION_ID,
APD.ACE_PAYD_LOCATION_CODE,
APD.ACE_PAYD_ORD_NUM ) TAB2
WHERE
TAB1.ACE_IT_REGION_ID = TAB2.ACE_PAYD_REGION_ID
AND TAB1.ACE_IT_LOCATION_CODE = TAB2.ACE_PAYD_LOCATION_CODE
AND TAB1.ACE_IT_ORD_NUM = TAB2.ACE_PAYD_ORD_NUM
AND TAB1.TOTAL_ITEM_PRICE_PER_ORDER = TAB2.TOTAL_ACE_PAYD_AMOUNT,
AND TAB1.ACE_ORD_COMPLETION_TIME IS NOT NULL
ORDER BY
TAB1.ACE_IT_REGION_ID,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM ) EX
To help optimize, I can suggest the following indexes as you do not have any such
displayed in your post of structures/indexes... The Payment Detail index is actually a covering index meaning is has the elements for the where, group by and the sum single field. This way it does not have to go to the raw table pages to do the query. It can all be performed directly from the indexed fields and each should be optimized for the join and where critreia.
table index on..
ACE_ORDERS ( ACE_ORD_TYPE, ACE_ORD_COMPLETION_TIME, ACE_ORD_REGION_ID, ACE_ORD_LOCATION_CODE, ACE_ORD_NUM, ACE_ORD_STATUS )
ACE_ITEM_TRAN ( ACE_IT_REGION_ID, ACE_IT_LOCATION_CODE, ACE_IT_ORD_NUM, ACE_IT_VOID_IND )
ACE_PAYMENT_DTL ( ACE_PAYD_POSTING_TIMESTAMP, ACE_PAYD_REGION_ID, ACE_PAYD_LOCATION_CODE, ACE_PAYD_ORD_NUM, ACE_PAYD_STATUS, ACE_PAYD_AMOUNT )

You need to rewrite the query using JOINS and ensure the fields being joined on have indexes.
Your revised query should be of this format:
SELECT tab1.fld1, tab.fld2
FROM tab1
JOIN tab2 ON (tab2.ID = tab1.ID AND tab2.fld3 = 'xxx')
JOIN tab3 ON (tab3.ID2 = tab2.ID2)
WHERE tab1.fld4 = 'aaa'
and tab3.fld5 > 100
This will allow the SQL optimizer to do its job.

SELECT /*+ PARALLEL(5) */
EXTER.ACE_IT_REGION_ID ,
EXTER.ACE_IT_LOCATION_CODE,
EXTER.ACE_IT_ORD_NUM,
EXTER.TOTAL_ITEM_PRICE_PER_ORDER,
EXTER.TOTAL_ACE_PAYD_AMOUNT,
EXTER.ACE_ORD_COMPLETION_TIME AS DATEOFDATA
FROM
(SELECT /*+ use_hash(TAB1,TAB2) +*/
DISTINCT
TAB1.ACE_IT_REGION_ID ,
TAB1.ACE_IT_LOCATION_CODE,
TAB1.ACE_IT_ORD_NUM,
TAB1.TOTAL_ITEM_PRICE_PER_ORDER,
TAB2.TOTAL_ACE_PAYD_AMOUNT,
TAB1.ACE_ORD_COMPLETION_TIME
FROM
(SELECT AAA.ACE_IT_REGION_ID,
AAA.ACE_IT_LOCATION_CODE,
AAA.ACE_IT_ORD_NUM,
AAA.SUM_PRICE_PLUS_TAX,
AAA.TOTAL_DISCOUNT,
-- There is no necessary that you write another subquery to finish below sql, you can do it in AAA
(AAA.SUM_PRICE_PLUS_TAX-AAA.TOTAL_DISCOUNT) AS TOTAL_ITEM_PRICE_PER_ORDER,
TRUNC(AAA.ACE_ORD_COMPLETION_TIME)
FROM (SELECT B.ACE_IT_REGION_ID AS ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE AS ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM AS ACE_IT_ORD_NUM,
(SUM(B.ACE_IT_ITEM_PRICE + B.ACE_IT_TAX_AMT)*B.ACE_IT_QTY) AS SUM_PRICE_PLUS_TAX,
SUM(B.ACE_IT_DISC_AMT+B.ACE_IT_AUTO_DISC_AMT) AS TOTAL_DISCOUNT,
TRUNC(A.ACE_ORD_COMPLETION_TIME ) AS ACE_ORD_COMPLETION_TIME
FROM POSDB.ACE_ORDERS A, POSDB.ACE_ITEM_TRAN B
WHERE
A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
-- you can remove it replace by trunc(A.ACE_ORD_COMPLETION_TIME) = TRUNC(SYSDATE -1) if there is no index on this column.
-- A.ACE_ORD_COMPLETION_TIME >= TRUNC(SYSDATE -1)
-- AND A.ACE_ORD_COMPLETION_TIME < TRUNC(SYSDATE)
AND A.ACE_ORD_REGION_ID = B.ACE_IT_REGION_ID
AND A.ACE_ORD_LOCATION_CODE = B.ACE_IT_LOCATION_CODE
AND A.ACE_ORD_NUM = B.ACE_IT_ORD_NUM
AND A.ACE_ORD_TYPE = 'IS'
AND (A.ACE_ORD_STATUS = 'CR'
OR A.ACE_ORD_STATUS IS NULL
-- I think it better to replace blow by OR INSTR(ACE_ORD_STATUS,' ') > -1
-- OR A.ACE_ORD_STATUS LIKE ' %'
-- OR A.ACE_ORD_STATUS LIKE '% '
)
AND (B.ACE_IT_VOID_IND <> 'V' OR B.ACE_IT_VOID_IND IS NULL )
GROUP BY B.ACE_IT_REGION_ID,
B.ACE_IT_LOCATION_CODE,
B.ACE_IT_ORD_NUM,
A.ACE_ORD_COMPLETION_TIME
) AAA
-- remove order by clause in subquery, it's useless.
-- ORDER BY AAA.ACE_IT_REGION_ID,
-- AAA.ACE_IT_LOCATION_CODE,
-- AAA.ACE_IT_ORD_NUM,
-- AAA.ACE_ORD_COMPLETION_TIME
) TAB1,
(SELECT ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM,
SUM(ACE_PAYD_AMOUNT) TOTAL_ACE_PAYD_AMOUNT
FROM POSDB.ACE_PAYMENT_DTL
WHERE ACE_PAYD_POSTING_TIMESTAMP BETWEEN TRUNC(SYSDATE-1) AND TRUNC(SYSDATE)
AND (ACE_PAYD_STATUS <> 'V' OR ACE_PAYD_STATUS IS NULL )
GROUP BY
ACE_PAYD_REGION_ID,
ACE_PAYD_LOCATION_CODE,
ACE_PAYD_ORD_NUM) TAB2
WHERE TAB1.ACE_IT_REGION_ID = TAB2.ACE_PAYD_REGION_ID
AND TAB1.ACE_IT_LOCATION_CODE = TAB2.ACE_PAYD_LOCATION_CODE
AND TAB1.ACE_IT_ORD_NUM = TAB2.ACE_PAYD_ORD_NUM
-- remove order by clause in subquery, it's useless.
--ORDER BY
-- TAB1.ACE_IT_REGION_ID ,
-- TAB1.ACE_IT_LOCATION_CODE,
-- TAB1.ACE_IT_ORD_NUM
) EXTER
WHERE (EXTER.TOTAL_ITEM_PRICE_PER_ORDER = EXTER.TOTAL_ACE_PAYD_AMOUNT)
AND EXTER.ACE_ORD_COMPLETION_TIME IS NOT NULL;
-- Fix it like this for tempory, please supply explain plan for further.
-- There are so many columns like "ACE_PAYD_STATUS is not null", as you know, index could not contain null value.
-- But I think you can create an similarly index like "create index *** on ACE_PAYMENT_DTL(ACE_PAYD_STATUS,0)" to keep null values in your index.

Related

check for a column if it is null , over a previous term with some conditions

I have lets say two terms term A (previous)and term B (current) , i need to check if pol_cancl_date is null or not in term A , there is a transaction_sequence_number , i need to see if the pol_cncl_date is existing in the greatest A.transaction_sequence_number and if greatest( A.transaction_sequence_number ) is the greated when compared to all B.transaction_sequence_number numbers , if it is then i would want to check for pol_cancl_dates's existence and apply a logic
WITH x AS (
SELECT * FROM (
SELECT
pol_num
,term_start_dt
,term_end_dt,pol_cancel_dt
,trans_seq_num
,future_cancel_dt
,DENSE_RANK() OVER (PARTITION BY pol_num ORDER BY term_end_dt DESC) AS flag
FROM `gcp-ent-datalake-preprod.trns_prop_pol_hs_horison.prop_cost`
--WHERE pol_num IN ('30766675','33896642')
-- pol_num = '33288489'
ORDER BY term_start_dt, term_end_dt DESC
)
)
SELECT
*
,CASE
WHEN prior_pol_cancel_dt IS NOT NULL AND current_trans_seq_num < prior_trans_seq_num THEN prior_pol_cancel_dt
ELSE current_pol_cancel_dt
END apply_cancelled_renewal_dt
FROM (
SELECT
MAX(a.pol_num) AS current_pol_num
,MAX(a.term_start_dt) AS current_term_start_dt
,a.term_end_dt AS current_term_ent_dt
,MAX(a.pol_cancel_dt) AS current_pol_cancel_dt
,MAX(a.trans_seq_num) AS current_trans_seq_num
,MAX(a.future_cancel_dt) AS current_future_cancel_dt
,MAX(a.flag) AS current_flag
,MAX(b.pol_num) AS prior_pol_num
,MAX(b.term_start_dt) AS prior_term_start_dt
,b.term_end_dt AS prior_term_end_dt
,MAX(b.pol_cancel_dt) AS prior_pol_cancel_dt
,MAX(b.trans_seq_num) AS prior_trans_seq_num
,MAX(b.future_cancel_dt) AS prior_future_cancel_dt
,MAX(b.flag) AS prior_flag
FROM (
SELECT * FROM x WHERE flag=1) a
INNER JOIN(
SELECT * FROM x WHERE flag = 2 ) b
ON a.pol_num = b.pol_num AND a.flag = b.flag - 1
WHERE a.pol_cancel_dt IS NOT NULL
AND b.pol_cancel_dt IS NOT NULL
AND greatest(a.trans_seq_num) < b.trans_seq_num
-- AND a.trans_seq_num = GREATEST(a.trans_seq_num)
-- AND b.trans_seq_num = GREATEST(b.trans_seq_num)
GROUP BY a.term_end_dt, b.term_end_dt
)
--WHERE a.term_start_dt < b.term_start_dt
--if prior term GREATEST (trans_sewq num
this logic is still not giving me some results , one thing is that trans_seq_num doesn't necessarily have to be one less

TERADATA, CASE INTO WHERE CLAUSE

I'd need help on this matter.
my where condition does not get accepted ... I know that is tricky the case in the where clause, so i think you could let me out... I created a field into a subquery with a over partition by, which then i bring into the main select ... then I'd need to apply the filter you see below... it returns me an error saying that B does not exist even tough if I just write B.CC = 1 then it gives me result...
any ideas?
Thanks in advance
SELECT
B.*
FROM
(
SELECT
A.*,
(Count(A.COD_ABI) Over (PARTITION BY A.COD_ABI, A.COD_KTO)) AS CC
FROM (
SELECT DISTINCT
T2.COD_PRODT_SALDO,
T2.COD_RESID_NPE,
T2.COD_DIVISA_UIC,
T2.COD_ABI,
T2.COD_NDG,
T2.COD_KTO,
T2.COD_PAESE_UIC_NPE,
T2.DAT_SCA,
T2.DAT_ACC,
T2.DAT_EST
FROM
(
SELECT
T1.COD_PRODT_SALDO
,T1.COD_RESID_NPE
,T1.COD_DIVISA_UIC
,T1.COD_ABI
,T1.COD_NDG
,'00753' ||T1.COD_PRODT_SALDO||T1.COD_CNTRT_SALDO AS COD_KTO
,T1.COD_CONTRATTO_SAL
,T1.COD_RIFER_ANNO
,T1.COD_RIFER_MESE
,T1.COD_RIFER_ANNO || T1.COD_RIFER_MESE AS COD_RIFER
,T1.COD_CONTB_ETR
,T1.DAT_EST
,T1.DAT_ACC
,T1.DAT_SCA
,T1.COD_PAESE_UIC_NPE
FROM ES777A.VA_ES_DB_ANAGR_CONTO AS T1,
ES777A.VE_BFD_PDC AS T2
WHERE T1.TMS_INIZIO_VALIDITA <= T2.TMS_PDC
AND T1.TMS_FINE_VALIDITA > T2.TMS_PDC
AND T1.TMS_CANC_FISICA IS NULL
AND T1.FLG_RIFACIMENTO = 0
AND T1.COD_ABI = T2.COD_ABI
AND T2.NOM_VISTA='VA_ES_DB_ANAGR_CONTO'
AND T2.NUM_PERIO_RIF = 20200131
AND T2.COD_PERIODICITA = 'G'
AND T1.COD_PRODT_SALDO NOT IN ('1398' , '1698')
AND T1.COD_PRODT_SALDO IN ('1801', '1803', '1901', '1903', '3301', '3304', '3311', '3401', '3411', '3421')
)
AS T2
INNER JOIN
(
SELECT
T1.COD_ABI,
'00753'||T1.COD_PRODT_SALDO||T1.COD_CNTRT_SALDO AS COD_KTO,
Max(T1.COD_RIFER_ANNO || COD_RIFER_MESE) AS MAX_COD_RIFER
FROM ES777A.VA_ES_DB_ANAGR_CONTO AS T1,
ES777A.VE_BFD_PDC AS T2
WHERE
T1.TMS_INIZIO_VALIDITA <= T2.TMS_PDC
AND T1.TMS_FINE_VALIDITA > T2.TMS_PDC
AND T1.TMS_CANC_FISICA IS NULL
AND T1.FLG_RIFACIMENTO = 0
AND T1.COD_ABI = T2.COD_ABI
AND T2.NOM_VISTA = 'VA_ES_DB_ANAGR_CONTO'
AND T2.NUM_PERIO_RIF = 20200131
AND T2.COD_PERIODICITA = 'G'
AND T1.COD_PRODT_SALDO NOT IN ('1398' , '1698')
AND T1.COD_PRODT_SALDO IN ('1801', '1803', '1901', '1903', '3301', '3304', '3311', '3401', '3411', '3421')
GROUP BY T1.COD_PRODT_SALDO,T1.COD_ABI,T1.COD_CNTRT_SALDO
)
AS T1
ON ( T2.COD_ABI = T1.COD_ABI AND T2.COD_KTO = T1.COD_KTO AND T2.COD_RIFER = T1.MAX_COD_RIFER )
WHERE
( T2.DAT_EST > '2019-11-02' OR T2.DAT_EST IS NULL ) -- -90GG
AND ( T2.DAT_SCA > '2019-11-02' OR T2.DAT_SCA IS NULL ) -- -90GG
)
A
)
B
WHERE b.cc =
WHEN (B.CC > 1 AND B.DAT_EST IS NOT NULL) THEN 1
WHEN (B.CC > 1 AND B.DAT_EST IS NULL) THEN 0
WHEN (B.CC = 1) THEN 1 ELSE 0
END
This answers the original version of the question.
In Teradata, you can simplify the logic to:
SELECT ...,
Count(A.COD_ABI) Over (PARTITION BY A.COD_ABI, A.COD_KTO) AS CC
FROM A
QUALIFY CC > 1 AND DATE_EST IS NOT NULL;
All the subqueries are unnecessary

How to Select * Where Everything is Distinct Except One Field

I'm trying to pull 6 records using the code below but there are some cases where the information is updated and therefore it is pulling duplicate records.
My code:
SELECT column2, count(*) as 'Count'
FROM ServiceTable p
join HIERARCHY h
on p.LOCATION_CODE = h.LOCATION
where Report_date between '2017-04-01' and '2017-04-30'
and Column1 = 'Issue '
and LOCATION = '8789'
and
( record_code = 'INCIDENT' or
(
SUBMIT_METHOD = 'Web' and
not exists
(
select *
from ServiceTable p2
where p2.record_code = 'INCIDENT'
and p2.incident_id = p.incident_id
)
)
)
The problem is that instead of the six records it is pulling eight. I would just use distinct * but the file_date is different on the duplicate entries:
FILE_DATE Incident_ID Column1 Column2
4/4/17 123 Issue Service - Red
4/4/17 123 Issue Service - Blue
4/5/17 123 Issue Service - Red
4/5/17 123 Issue Service - Blue
The desired output is:
COLUMN2 COUNT
Service - Red 1
Service - Blue 1
Any help would be greatly appreciated! If you need any other info just let me know.
If you turn your original select statement without the aggregation function into a subquery, you can distinct that on your values that are not the changing date, then select a COUNT from there. Don't forget your GROUP BY clause at the end.
SELECT Column2, COUNT(Incident_ID) AS Service_Count
FROM (SELECT DISTINCT Incident_ID, Column1, Column2
FROM ServiceTable p
JOIN HIERARCHY h ON p.LOCATION_CODE = h.LOCATION
WHERE Report_date BETWEEN '2017-04-01' AND '2017-04-30'
AND Column1 = 'Issue '
AND LOCATION = '8789'
AND
( record_code = 'INCIDENT' or
(
SUBMIT_METHOD = 'Web' and
NOT EXISTS
(
SELECT *
FROM ServiceTable p2
WHERE p2.record_code = 'INCIDENT'
AND p2.incident_id = p.incident_id)
)
)
)
GROUP BY Column2
Also, if you are joining tables it is a good practice to fully qualify the field you are selecting. Example: p.Column2, p.Incident_ID, h.LOCATION. That way, even your distinct fields are easier to follow where they came from and how they relate.
Finally, don't forget that COUNT is a reserved word. I modified your alias accordingly.
If you are using an aggregation function (count), you should use group by for the column not in the aggregation function:
SELECT column2, count(*) as 'Count'
FROM ServiceTable p
join HIERARCHY h
on p.LOCATION_CODE = h.LOCATION
where Report_date between '2017-04-01' and '2017-04-30'
and Column1 = 'Issue '
and LOCATION = '8789'
and
( record_code = 'INCIDENT' or
(
SUBMIT_METHOD = 'Web' and
not exists
(
select *
from ServiceTable p2
where p2.record_code = 'INCIDENT'
and p2.incident_id = p.incident_id
)
)
)
group by column2

how to use case with group by?

the query works well but when iam adding group by it gives me [Error] ORA-01427 here is the main query
SELECT DISTINCT Contract_number,
area_number,
area_name,
ADVANCE_PAY,
Postponed_Amount,
extract_number,
total
FROM (SELECT xxr.Contract_num Contract_number,
xxr.p_area_no area_number,
xxr.p_area_name area_name,
xxr.ADVANCE_PAY ADVANCE_PAY,
xxr.DEFERRED_BOOST Postponed_Amount,
xxr.release_num extract_number,
and here is the case statement :
(SELECT DISTINCT
CASE
WHEN :p_item_code IS NOT NULL
THEN
TOTAL_AMOUNT
WHEN :p_item_code IS NULL
THEN
( (SELECT NVL (SUM (TOTAL_AMOUNT), 0)
FROM XXEXTRACT.XXNATGAS_REALSES_LINES
WHERE XXEXTRACT.XXNATGAS_REALSES.release_id =
XXEXTRACT.XXNATGAS_REALSES_LINES.release_id))
ELSE
NULL
END
FROM XXEXTRACT.XXNATGAS_REALSES_LINES xxrl,
XXEXTRACT.XXNATGAS_REALSES
WHERE 1 = 1
AND xxrl.release_id =
XXEXTRACT.XXNATGAS_REALSES.release_id)
AS total
and here is the from part :
FROM XXEXTRACT.XXNATGAS_REALSES_LINES xxrl,
XXEXTRACT.XXNATGAS_REALSES xxr
WHERE 1 = 1
AND xxrl.release_id = xxr.release_id
AND xxr.release_date >= NVL (:p_date_from, xxr.release_date)
AND xxr.release_date <= NVL (:p_date_to, xxr.release_date)
AND xxr.Contract_num = NVL (:p_cont_num, xxr.Contract_num)
AND xxr.vendor_id = NVL (:p_ven_id, xxr.vendor_id)
AND xxr.vendor_site_id = NVL (:p_site_id, xxr.vendor_site_id)
)
and here is the group by :
GROUP BY Contract_number,
area_number,
area_name,
ADVANCE_PAY,
Postponed_Amount,
extract_number,
total;
these is the full query so please any help
For sure I couldn't understand very well your query. You could improve your post for next time.
As answer, I think you should encapsulate your select statment and group by using your select as subquery. It is not the best approach but it may works fine.
select *
from (
select distinct Contract_number
,area_number
,area_name
,ADVANCE_PAY
,Postponed_Amount
,extract_number
,total
from (
select xxr.Contract_num Contract_number
,xxr.p_area_no area_number
,xxr.p_area_name area_name
,xxr.ADVANCE_PAY ADVANCE_PAY
,xxr.DEFERRED_BOOST Postponed_Amount
,xxr.release_num extract_number
,(
select distinct case
when :p_item_code is not null
then TOTAL_AMOUNT
when :p_item_code is null
then (
(
select NVL(SUM(TOTAL_AMOUNT), 0)
from XXEXTRACT.XXNATGAS_REALSES_LINES
where XXEXTRACT.XXNATGAS_REALSES.release_id = XXEXTRACT.XXNATGAS_REALSES_LINES.release_id
)
)
else null
end
from XXEXTRACT.XXNATGAS_REALSES_LINES xxrl
,XXEXTRACT.XXNATGAS_REALSES
where 1 = 1
and xxrl.release_id = XXEXTRACT.XXNATGAS_REALSES.release_id
) as total
from XXEXTRACT.XXNATGAS_REALSES_LINES xxrl
,XXEXTRACT.XXNATGAS_REALSES xxr
where 1 = 1
and xxrl.release_id = xxr.release_id
and xxr.release_date >= NVL(:p_date_from, xxr.release_date)
and xxr.release_date <= NVL(:p_date_to, xxr.release_date)
and xxr.Contract_num = NVL(:p_cont_num, xxr.Contract_num)
and xxr.vendor_id = NVL(:p_ven_id, xxr.vendor_id)
and xxr.vendor_site_id = NVL(:p_site_id, xxr.vendor_site_id)
)
) TBL1
group by TBL1.Contract_number
,TBL1.area_number
,TBL1.area_name
,TBL1.ADVANCE_PAY
,TBL1.Postponed_Amount
,TBL1.extract_number
,TBL1.total;

Erroneous ORA-01427: single-row subquery returns more than one row

I'm getting the error [ORA-01427: single-row subquery returns more than one row] when I execute a query. I have a query structured like so:
SELECT LV.PRICE,
(SELECT C.MODEL_NAME FROM CARS C WHERE C.MODEL_ID = LV.MODEL_ID) as MODEL_NAME
FROM LEDGER_VIEW LV
WHERE LV.PRICE < 500
It's breaking on the nested select. I know the logic both in the view and in this query is correct, and that there's no chance of the nested select returning more than one row. The CARS table's MODEL_ID is a unique field. If I execute the query without the nested select it doesn't return this error.
The LEDGER_VIEW is a view built on top of another view. Is it possible that these stacked views are buggy in Oracle 10g? I don't know how else to debug this problem.
I am aware I could change this particular query to a join rather than a nested select, but I'd like to know why this is happening because I use nested queries in other places where it is not so easily modifiable.
EDIT: Here's the really strange thing. The LEDGER_VIEW is, as I said, built on top of another view. As a test, I copied the nested view's SQL directly into the SQL of the SQL of LEDGER_VIEW, in place of the nested view, and it returned with no errors (as expected). This seems to confirm to me that there is some buggy behavior either with nested views or with the combination of nested views + database links.
Your subquery is returning multiple rows. Use the query below to find out which MODELID values in the Car table are duplicated:
select MODELID as CarsModelID, count(*) as Count
from cars
where MODELID in (
select MODEL_ID
from LEDGER_VIEW
WHERE LV.PRICE < 500
)
group by MODELID
having count(*) > 1
I am unable to recreate via a creation of a stacked view. (althoug RedFilters will find the culprit)
CREATE TABLE t1
(
t1_id NUMBER ,
txt VARCHAR2( 50 ),
CONSTRAINT t1_pk PRIMARY KEY( t1_id )
) ;
CREATE TABLE t2
(
t2_id NUMBER ,
t1_id NUMBER ,
price NUMBER( 10, 4 ) ,
CONSTRAINT t2_pk PRIMARY KEY( t2_id ),
CONSTRAINT t2_fk FOREIGN KEY( t1_id ) REFERENCES t1( t1_id )
);
insert into t1(t1_id, txt) values(1,'fit');
insert into t1(t1_id, txt) values(2,'focus');
insert into t1(t1_id, txt) values(3,'golf');
insert into t1(t1_id, txt) values(4,'explorer');
insert into t1(t1_id, txt) values(5,'corolla');
insert into t2(t2_id, t1_id, price) values(1,1,17000);
insert into t2(t2_id, t1_id, price) values(2,2,16000);
insert into t2(t2_id, t1_id, price) values(3,3,22000);
insert into t2(t2_id, t1_id, price) values(4,4,31000);
insert into t2(t2_id, t1_id, price) values(5,5,17000);
create view t1_view as select * from t1;
create view t2_view as select * from t2;
create view t_stacked_view as
select t1_view.txt ,
t2_view.price ,
t1_view.t1_id
from t1_view
left join
t2_view
on t1_view.t1_id = t2_view .t1_id
;
--stacked view test
select t1_view.txt ,
(select t_stacked_view.price
from t_stacked_view
where t1_view.t1_id = t_stacked_view .t1_id) price
from t1_view ;
--or better yet, just drop the row level query
select t1_view.txt ,
t2_view.price
from t1_view
left join
t2_view
on t1_view.t1_id = t2_view .t1_id
;
But that begs the question, why are you doing the row level query here? While 10g ought to optimize them the same, I have always found it easier to write queries as below, both for readability, maintainability, and to specifically avoid the error you are having (is it always, 3 years down the road, guaranteed by the application (both in the db and the calling app) that you cannot have a condition that will cause this error? One rouge statement gets in and your entire app dies?
SELECT LV.PRICE,
c.model_name
FROM LEDGER_VIEW LV
LEFT /* OR INNER */ JOIN CARS C
ON C.MODEL_ID = LV.MODEL_ID
WHERE LV.PRICE < 500
I suggest using RedFilter's answer to check whether there are multiple cars with a given MODEL_ID.
If you're absolutely certain that CARS.MODEL_ID is unique, then it implies that the error message is generated by selection from LEDGER_VIEW - so try running the equivalent query without the subquery on CARS, like so:
SELECT LV.PRICE
FROM LEDGER_VIEW LV
WHERE LV.PRICE < 500
If you still see the same error (you should, if CARS.MODEL_ID is unique) you will need to debug LEDGER_VIEW - ie. check for sub-queries returning multiple rows in LEDGER_VIEW and the underlying views it is based on.
Creating views based on views is possible in most forms of SQL, but it is usually a bad idea - for this very reason.
Try forcing your subquery to return a single result by appending rownum = 1, like this:
SELECT LV.PRICE,
(SELECT C.MODEL_NAME FROM CARS C WHERE C.MODEL_ID = LV.MODEL_ID AND ROWNUM = 1) as MODEL_NAME
FROM LEDGER_VIEW LV
WHERE LV.PRICE < 500
It will probably work and if it does, you will know that your subquery returns multiple rows, which judging by the error code it should be. Of course this is not a solution so you might have to fix your data in cars table to actually solve the problem. Leaving and rownum = 1 will eliminate the error if model_id is duplicated again, preventing you from noticing the problem.
select
a.account_number,
a.party_id,
a.TRX_NUMBER,
a.trx_date,
a.order_number,
adv.unapplied_amt,
a.Finance,
a.customer_name,a.PARTY_NAME,
a.customer_number,a.contact_number,
a.name,
a.Aging,
a.transaction_type,
a.exec_name,
a.team_leader,
sum(a.O_SAmount),
(case when (trunc(sysdate) - trunc(a.trx_date)) <=:ag1 then sum(a.O_SAmount) else 0 end ) bucket1,--"<" || :ag1,
(case when (trunc(sysdate) - trunc(a.trx_date)) between :ag1+1 and :ag2 then sum(a.O_SAmount) else 0 end ) bucket2,--:ag1+1 || "to" || :ag2,
(case when (trunc(sysdate) - trunc(a.trx_date)) between :ag2+1 and :ag3 then sum(a.O_SAmount) else 0 end ) bucket3,--:ag2+1 || "to" || :ag3,
(case when (trunc(sysdate) - trunc(a.trx_date)) >:ag3 then sum(a.O_SAmount) else 0 end ) bucket4,
:AS_ON_date
from
(select distinct hca.account_number,hp.party_id,--rcta.CUSTOMER_TRX_ID,
--rcta.trx_number,rcta.trx_date,apsa.due_date,
(
select distinct
--ooha.order_number,
rcta.trx_number
--to_char(rcta.trx_date,'DD-MON-YYYY') trx_date
from
ra_customer_trx_all rcta,
oe_order_headers_all ooh,
oe_order_lines_all oola,
--ra_customer_trx_all rcta,
ra_customer_trx_lines_all rctla,
ra_cust_trx_types_all rctta
--ra_customer_trx_lines_all rctl
where 1=1
AND ooh.header_id = oola.header_id
--AND ooh.order_number = '111111010101698'
AND ooh.order_number=oohA.order_number
AND TO_CHAR (ooh.order_number) = rcta.ct_reference
AND rcta.customer_trx_id = rctla.customer_trx_id
AND rctla.inventory_item_id = oola.inventory_item_id
and rcta.CUST_TRX_TYPE_ID = rctta.cust_trx_type_id
and rcta.org_id = rctta.org_id
and rctta.type like 'INV'
and oola.ordered_item LIKE 'MV%'
AND oola.attribute3 = 'Y'
AND ooh.flow_status_code <> 'ENTERED'
AND oola.flow_status_code <> 'CANCELLED'
)TRX_NUMBER,
(select distinct
--ooha.order_number,
--rcta.trx_number
rcta.trx_date
from
ra_customer_trx_all rcta,
oe_order_headers_all ooh,
oe_order_lines_all oola,
--ra_customer_trx_all rcta,
ra_customer_trx_lines_all rctla,
ra_cust_trx_types_all rctta
--ra_customer_trx_lines_all rctl
where 1=1
AND ooh.header_id = oola.header_id
--AND ooh.order_number = '111111010101698'
AND ooh.order_number=oohA.order_number
AND TO_CHAR (ooh.order_number) = rcta.ct_reference
AND rcta.customer_trx_id = rctla.customer_trx_id
AND rctla.inventory_item_id = oola.inventory_item_id
and rcta.CUST_TRX_TYPE_ID = rctta.cust_trx_type_id
and rcta.org_id = rctta.org_id
and rctta.type like 'INV'
and oola.ordered_item LIKE 'MV%'
AND oola.attribute3 = 'Y'
AND ooh.flow_status_code <> 'ENTERED'
AND oola.flow_status_code <> 'CANCELLED'
)TRX_Date,
rcta.INTERFACE_HEADER_ATTRIBUTE1 order_number,
ooha.attribute10 Finance,
f.customer_name,HP.PARTY_NAME,
TO_NUMBER(f.customer_number)customer_number,hp.primary_phone_number contact_number,--csi.incident_number,
--cii.instance_number,
haou.name,
--sum(acr.amount) Advance,--rcta.CUST_TRX_TYPE_ID,--acr.cash_receipt_id,
--sum(abs((apsa.AMOUNT_DUE_REMAINING-nvl(acr.amount,0)))) "O_SAmount",
apsa.AMOUNT_DUE_REMAINING O_SAmount,
--sum(abs((apsa.AMOUNT_DUE_REMAINING))) "O_SAmount",
round(months_between(sysdate,rcta.trx_date)*30) Aging,
--(case when ((round(months_between(sysdate,rcta.trx_date)*30)>=0) or (round(months_between(sysdate,rcta.trx_date)*30)<:aging1)) then apsa.AMOUNT_DUE_REMAINING end) "0 TO 30"
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) <=:ag1 then apsa.AMOUNT_DUE_REMAINING else 0 end ) bucket1,--"<" || :ag1,
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) between :ag1+1 and :ag2 then apsa.AMOUNT_DUE_REMAINING else 0 end ) bucket2,--:ag1+1 || "to" || :ag2,
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) between :ag2+1 and :ag3 then apsa.AMOUNT_DUE_REMAINING else 0 end ) bucket3,--:ag2+1 || "to" || :ag3,
--(case when (trunc(sysdate) - trunc(apsa.Due_Date)) >:ag3 then apsa.AMOUNT_DUE_REMAINING else 0 end ) bucket4,
--apsa.amount_due_original,
--TO_NUMBER(apsa.AMOUNT_DUE_REMAINING)AMOUNT_DUE_REMAINING,
rctta.name transaction_type,
PAPF.full_name||'-'||PAPF.EMPLOYEE_NUMBER exec_name,
ooha.attribute9 team_leader,
:AS_ON_date
from ra_customer_trx_all rcta,
oe_order_headers_all ooha,
hz_cust_accounts hca,
hz_parties hp,
--cs_incidents_all_b csi,
--csi_item_instances cii,
hr_all_organization_units haou,
ar_cash_receipts_all acr,
ar_receivable_applications_all aaa,
ra_cust_trx_types_all RCTTA,
hr.per_all_people_f papf,
ar_customers f,
ar_payment_schedules_all apsa,
jtf.JTF_RS_SALESREPS jrs
where 1=1
--and INTERFACE_HEADER_ATTRIBUTE1 like '111111060100538'
--and INTERFACE_HEADER_ATTRIBUTE1 like '111111010105402'
--and INTERFACE_HEADER_ATTRIBUTE1 like '111111010102791'
and rcta.ct_reference(+)=TO_CHAR(ooha.order_number)
AND f.customer_id = (rcta.bill_to_customer_id)
and f.customer_id=hca.cust_account_id
and hca.party_id=hp.party_id
and haou.organization_id=rcta.INTERFACE_HEADER_ATTRIBUTE10
--and hp.party_id=cii.owner_party_id
--and csi.inventory_item_id=cii.inventory_item_id
--and csi.inv_organization_id=haou.organization_id
--and haou.organization_id=nvl(:location,haou.organization_id)
and ooha.SHIP_FROM_ORG_ID=nvl(:location,haou.organization_id)
AND RCTTA.NAME like :transaction_type||'%'
--decode(:org_id,null,null,(select name from ar_cash_receipts_all where organization_id = :org_id)) ||'%')
and rcta.trx_date<=to_date(:AS_ON_date)
--AND RCTTA.NAME=NVL(:TRANS_TYPE,RCTTA.NAME)
and rcta.org_id=nvl(:org_id,rcta.org_id)
--and f.customer_name like 'VIKAS SATAV'
and aaa.applied_customer_trx_id(+)=rcta.customer_trx_id
and aaa.cash_receipt_id=acr.cash_receipt_id(+)
and rcta.status_trx like 'OP'
and rcta.CUST_TRX_TYPE_ID=rctta.CUST_TRX_TYPE_ID
and apsa.CUSTOMER_TRX_ID=rcta.CUSTOMER_TRX_ID
and TO_NUMBER(apsa.AMOUNT_DUE_REMAINING) >0
--and hp.party_id=papf.party_id(+)
and jrs.salesrep_id = ooha.SALESREP_ID
and jrs.ORG_ID = ooha.ORG_ID
and jrs.PERSON_ID = papf.PERSON_ID(+)
) a,
(
select
b.order_number,
sum(b.AMOUNT_APPLIED) unapplied_amt
from
(select distinct to_char(ooha.order_number) order_number,ara.* from
oe_order_headers_all ooha,
oe_payments oe,
ar_receivable_applications_all ara
where 1=1--ooha.order_number = :p_order_num
and oe.header_id=ooha.header_id
and ara.PAYMENT_SET_ID=oe.PAYMENT_SET_ID
and ara.DISPLAY='Y'
and (ara.STATUS like 'OTHER ACC' or ara.STATUS like 'UNAPP') --or ara.STATUS like 'ACC')
) b
group by b.order_number
) adv
where adv.order_number(+)=a.order_number
group by a.account_number,
a.party_id,
a.TRX_NUMBER,
a.trx_date,
a.order_number,
adv.unapplied_amt,
a.Finance,
a.customer_name,a.PARTY_NAME,
a.customer_number,a.contact_number,
a.name,
a.Aging,
a.transaction_type,
a.exec_name,
a.team_leader
order by a.Aging desc