In Putty, how do you locate where an error is based on the char position? - sql

I received the following error, which is based off of my code (attached below) in Netezza .
^ found "WHERE" (at char 543) expecting an identifier found a keyword
But how I find where in the code this is located at? Do I need to divide 543 by the amount of characters per line ?
the code is shown below :
DELETE FROM TDM_FEE_DISCOUNT_FACT;;
----------------------------------------------------------------------------
-- INSERT INTO TDM TABLE ---
----------------------------------------------------------------------------
INSERT INTO FEE_DISCOUNT_FACT
(
FEE_DISCNT_F_DK ,
HLTH_PLN_GRP_DK,
HLTH_PLN_SPSR_DK,
PLN_MBR_DK,
COV_PRD_STRT_DT,
COV_PRD_END_DT,
BIL_DUE_DT,
FEE_AMT,
DISCNT_AMT,
BIL_ID,
SS_CD,
TNT_CD,
INSRT_DT,
UPDT_DT,
CREAT_RUN_CYC_EXEC_SK,
LST_UPDT_RUN_CYC_EXEC_SK,
REC_PRCS_TYP_CD,
ROW_EFF_STRT_DT,
ROW_EFF_END_DT,
CUR_ROW_IND
)
WITH LAST_RUN_DATE(DT) AS
(
SELECT NVL(LAST_RUN, TO_DATE('01/01/1900', 'MM/DD/YYYY'))
FROM (
SELECT MAX(NVL(TCT.MANIFEST_COMPLETED_TS, TO_DATE('01/01/1900', 'MM/DD/YYYY'))) LAST_RUN
FROM :DB_XREF..TGT_CONTROL_TBL TCT
WHERE MANIFEST = 'F_FEE_DISCOUNT'
) T
)
,
--Need to modify the following section , on line 66 of FEE_DISCOUNT_FACT
DRIVER AS
(
select
PM.HLTH_PLN_GRP_NBR||'|'||SBFD.SS_CD AS HLTH_PLN_GRP_BK
,PM.HLTH_PLN_GRP_NBR AS SPSR_ID
,PM.PLN_MBR_SK
--COV_PRD_STRT_DT
--COV_PRD_END_DT
,SBFD.BIL_DUE_DT AS BIL_DUE_DT
,NVL(SBFD.FEE_AMT,0) AS FEE_AMT
,NVL(SBFD.DISCNT_AMT,0) AS DISCNT_AMT
,SBFD.BIL_ID
,SBFD.SS_CD
,SBFD.FEE_DISCNT_CREAT_DT_TM
from MBRBOR_TGT_D4..SUBSCRIBER_BILLING_FEE_DISCOUNT SBFD
LEFT OUTER JOIN MBRBOR_TGT_D4..PLAN_MEMBER PM
ON PM.SBSCR_SK = SBFD.SBSCR_SK
AND PM.CUR_ROW_IND = 'Y'
AND PM.REC_PRCS_TYP_CD <> 'D'
AND PM.SBSCR_DPND_RLNSP_TYP_CD_SK IN (SELECT CD_MAP_SK FROM REFBOR_TGT_D4..CODEMAP
WHERE CONFOR_CD = 'SUB')
)
/* IN the code, only need to join to the dimensions .. FACT DK's are the sequence */
SELECT NEXT VALUE FOR FEE_DISCOUNT_F_SEQ AS FEE_DISCNT_F_DK,
NVL(HPGD.HLTH_PLN_GRP_DK,-9) AS HLTH_PLN_GRP_DK,
NVL(HPGD.HLTH_PLN_SPSR_DK,-9) AS HLTH_PLN_SPSR_DK,
PM.PLN_MBR_SK AS PLN_MBR_DK,
NVL(??.COV_PRD_STRT_DT,-9) AS COV_PRD_STRT_DT,
NVL(??.COV_PRD_END_DT,-9) AS COV_PRD_END_DT,
NVL(BIL_DUE_DT,0) AS BIL_DUE_DT,
NVL(FEE_AMT, 0) AS FEE_AMT,
NVL(DISCNT_AMT, 0) AS DISCNT_AMT,
NVL(BIL_ID,-9) AS BIL_ID,
DR.SS_CD AS SS_CD,
'BSC' AS TNT_CD,
NOW() AS INSRT_DT,
NOW() AS UPDT_DT,
NVL(SBFD.CREAT_RUN_CYC_EXEC_SK,-9) AS CREAT_RUN_CYC_EXEC_SK,
NVL(SBFD.LST_UPDT_RUN_CYC_EXEC_SK,-9) AS LST_UPDT_RUN_CYC_EXEC_SK,
NVL(SBFD.REC_PRCS_TYP_CD,0) AS REC_PRCS_TYP_CD,
NVL(SBFD.ROW_EFF_STRT_DT,0) AS ROW_EFF_STRT_DT,
NVL(SBFD.ROW_EFF_END_DT,0) AS ROW_EFF_END_DT,
NVL(SBFD.CUR_ROW_IND,0) AS CUR_ROW_IND --FEE_DISCNT_CREAT_DT_TM
FROM DRIVER DR
LEFT OUTER JOIN :DB_TGT..HEALTH_PLAN_GROUP_DIMENSION HPGD ON DR.HLTH_PLN_GRP_BK = HPGD.HLTH_PLN_GRP_BK
AND FEE_DISCNT_CREAT_DT_TM BETWEEN HPGD.ROW_EFF_STRT_DT AND HPGD.ROW_EFF_END_DT
LEFT OUTER JOIN :DB_TGT..HEALTH_PLAN_SPONSOR_DIMENSION HPSD ON DR.SPSR_ID = HPSD.SPSR_ID
AND FEE_DISCNT_CREAT_DT_TM BETWEEN HPSD.ROW_EFF_STRT_DT AND HPSD.ROW_EFF_END_DT --DONE
--some of the joins will have different conditions . like for SS_CD it will be different
LEFT OUTER JOIN :DB_TGT..PLAN_MEMBER_DIMENSION PMD ON DR.PLN_MBR_SK = PMD.PLN_MBR_SK
AND FEE_DISCNT_CREAT_DT_TM BETWEEN PMD.ROW_EFF_STRT_DT AND PMD.ROW_EFF_END_DT
--LEFT OUTER JOIN
LEFT OUTER JOIN
(SELECT SBSCR.PLN_MBR_DK AS SBSCR_DK, PM.*
FROM :DB_TGT..PLAN_MEMBER_DIMENSION PM
LEFT OUTER JOIN
(SELECT PM.PLN_MBR_DK, PM.PLN_MBR_SK, PM.SBSCR_SK, PM.CUR_ROW_IND, PM.ROW_EFF_STRT_DT, PM.ROW_EFF_END_DT FROM
:DB_TGT..PLAN_MEMBER_DIMENSION PM WHERE PLN_MBR_SK = SBSCR_SK) SBSCR
ON PM.SBSCR_SK = SBSCR.SBSCR_SK AND (PM.ROW_EFF_END_DT -1) BETWEEN
SBSCR.ROW_EFF_STRT_DT AND SBSCR.ROW_EFF_END_DT) PMD
ON DR.PLN_MBR_SK = PMD.PLN_MBR_SK
AND DR.CAPITN_ERN_FROM_DT BETWEEN PMD.ROW_EFF_STRT_DT AND PMD.ROW_EFF_END_DT
Thanks

Since vi is the editor used for the queries (if you're in nzsql) - you can navigate 543 characters from the start by typing in 0543l in the editor - this will take you the start, then 543 steps to the "right". This should bring you to the area of the sql where the problem is.

Related

How to combine multiple complex queries?

There is a query that displays data by id (R_PERS_ACCOUNT_ID) and date (MAX(RBS.CREATE_DATE))
Select rpao.r_pers_account_id, max(rbs.create_date)
from r_base_trans rbs
join r_pers_acc_operation rpao on rbs.r_base_trans_id = rpao.r_base_trans_id
where rbs.create_date between to_date('01.12.2017', 'dd.mm.yyyy') and to_date('31.12.2020', 'dd.mm.yyyy')
and rbs.M_BASE_TRANS_TYPE_ID NOT IN 26
and ROWNUM < 100
group by rpao.r_pers_account_id;
enter image description here
There is one more request in which you need to insert data from the previous select. In the where clause where pa.r_pers_account_id, you need to insert the id from the previous table. And in to_date('31-01-2018', 'dd-mm-yyyy') there is also date data from the previous table. (In my case, I manually inserted only one data)
select TP.IIN_BIN,
pa.r_pers_account_id,
pa.close_date,
kbk.kbk_code,
org.code_nk,
org.CODE_TPK,
op.m_operation_type_id,
pa.open_date,
sum(op.amount)
from r_pers_account pa
join r_tax_payer tp on pa.r_tax_payer_id = tp.r_tax_payer_id
join r_pers_acc_operation op on op.r_pers_account_id = pa.r_pers_account_id
join m_kbk kbk on kbk.m_kbk_id = pa.m_kbk_id
join m_tax_org org on org.m_tax_org_id = pa.m_tax_org_id
where pa.r_pers_account_id in (16616864)
and is_charge_fine = 0
and trunc(op.actual_date, 'fmdd') <= to_date('31-01-2018', 'dd-mm-yyyy')
and op.m_operation_type_id = 1
group by tp.IIN_BIN, pa.r_pers_account_id, pa.close_date, kbk.kbk_code, op.m_operation_type_id, org.code_nk,
org.code_tpk, pa.open_date;
enter image description here
In this select, you also need to insert data by id and date.
select TP.IIN_BIN,
pa.r_pers_account_id,
pa.close_date,
kbk.kbk_code,
org.code_nk,
org.CODE_TPK,
op.m_operation_type_id,
pa.open_date,
sum(op.amount)
from r_pers_account pa
join r_tax_payer tp on pa.r_tax_payer_id = tp.r_tax_payer_id
join r_pers_acc_operation op on op.r_pers_account_id = pa.r_pers_account_id
join m_kbk kbk on kbk.m_kbk_id = pa.m_kbk_id
join m_tax_org org on org.m_tax_org_id = pa.m_tax_org_id
where pa.r_pers_account_id in (16616864)
and is_charge_fine = 0
and trunc(op.actual_date, 'fmdd') <= to_date('31-01-2018', 'dd-mm-yyyy')
and op.m_operation_type_id = 2
group by tp.IIN_BIN, pa.r_pers_account_id, pa.close_date, kbk.kbk_code, op.m_operation_type_id, org.code_nk,
org.code_tpk, pa.open_date;
enter image description here
It is necessary to make so that these 3 requests were one select.
In addition, after combining these queries, you need to display data by condition if the second select column sum(op.amount) has a negative number, and the third select column sum(op.amount) has 0 or a positive number
I don't quite understand what queries you posted do (2nd and 3rd look just the same to me), but - generally speaking - if you want to "reuse" one query in queries that follow, there's a useful option: CTE (common table expression, i.e. the WITH factoring clause).
Simplified, it would look like this; I hope you'll manage to apply it to your code:
with
first_query as
(select rpao.r_pers_account_id, ...
from ...
where ...
),
second_query as
(select tp.iin_bin, ...
from FIRST_QUERY f1 join r_per_account pa on ...
--------------
-- this is new!
join ...
where ...
),
third_query as
(select tp.iin_bin, ...
from ...
-- use SECOND_QUERY (and/or FIRST_QUERY, if you have to)
where ...
)
-- Finally: extract data you really need
select ...
from third_query t3
where ...

Oracle SQL Query Optimization (Left joins, indexes)

The following query gets stuck when a table is added in left join set. The query runs smooth if last join is excluded. but gets stuck if last join is included. I have tried ALL_ROWS, FIRST_ROWS optimizer hints as well. There are around 5500 expected rows from cps_taskhis for '20190404'.
Notes:
Table cpsmgt.cps_orderhis.orderid is indexed column. {screenshot 1}.
Table cpsmgt.cps_taskhis.orderid is also an indexed column which is being joined to cpsmgt.cps_orderhis.orderid in last left join. {screenshot 2}
Screen shot 1:
Screen shot 2:
SQL Query
SELECT /*FIRST_ROWS*/
t.taskid task_no,
t.orderid order_id,
DECODE(t.priority,50,'Low',100,'Medium',200,'High','Other') task_priority,
t.taskname task_name,
TO_CHAR(t.createtime,'HH24') creation_hour,
t.createtime create_time,
t.completedtime completed_time,
( to_timestamp(t.completedtime,'yyyy-mm-dd hh24:mi:ss') - to_timestamp(t.createtime,'yyyy-mm-dd hh24:mi:ss') ) time_difference,
op1.user_name initiator_login,
rd1.name role_assigned_maker,
op2.user_name checker_login,
rd2.name role_assigned_checker,
t.taskstate task_state,
t.tasktype task_type,
t.description task_description,
ord_comment.commenttext, -- 2048 byte varchar2
sim.msisdn target_msisdn,
o.reason reason_of_task, -- 2048 byte varchar2
DECODE(t.bussinesscategory,'0','Business Operation','1','Transaction and Action','2','Financial','3','Manual Task','4','Bulk','5'
,'Configuration','Others:'
|| t.bussinesscategory) businesscategory_of_task
FROM
cpsmgt.cps_taskhis t --PARTITION ( SYS_P30212 ) t
LEFT JOIN cpsmgt.cps_operator op1 ON op1.operator_id = t.createid
LEFT JOIN cpsmgt.cps_operator op2 ON op2.operator_id = t.ownerid
LEFT JOIN cpsmgt.cps_role_operator ro1 ON op1.operator_id = ro1.operator_id
AND op1.status <> '06'
LEFT JOIN cpssys.cps_role_def rd1 ON rd1.role_id = ro1.role_id
AND rd1.status = '30'
LEFT JOIN cpsmgt.cps_role_operator ro2 ON op2.operator_id = ro2.operator_id
AND op2.status <> '06'
LEFT JOIN cpssys.cps_role_def rd2 ON rd2.role_id = ro2.role_id
AND rd2.status = '30'
LEFT JOIN cpsmgt.cps_order_comment ord_comment ON t.orderid = ord_comment.orderid
LEFT JOIN cpsmgt.cps_sim_device sim ON t.on_identity_id = sim.identity_id
LEFT JOIN cpsmgt.cps_orderhis o ON t.orderid = o.orderid
WHERE
t.createtime BETWEEN TO_DATE(TO_CHAR(20190404)
|| ' 00:00:00','yyyy-mm-dd hh24:mi:ss') AND TO_DATE(TO_CHAR(20190404)
|| ' 23:59:59','yyyy-mm-dd hh24:mi:ss')
AND t.procdefid IN (
'IC_EditP2PMSISDNWorkflow',
'IC_ResetCustomerPinWorkflow',
'TC_TransactionConfirmWorkflow',
'IC_ChangeCustomerProductWorkflow',
'IC_EditG2PMSISDNWorkflow',
'IC_ChangeCustomerIdentityStatusWorkflow',
'TC_CancelRemittanceWorkflow',
'IC_ChangeCustomerMSISDNWorkflow',
'IC_ResetOrgOperatorPINWorkflow',
'IC_MigrateCustTrustL1Workflow',
'IC_MigrateCustTrustL2Workflow',
'IC_ChangeCustomerIdentityKYCWorkflow',
'IC_UnblockPaymentTransactionWorkflow',
'IC_ResetOrgOperatorPasswordWorkflow'
)
AND rd1.name IN (
'Complaints (Maker)',
'MFS 1344 Help Line',
'MFS 4444 Helpline',
'Operator user(back end user) maker',
'Complaints Checker',
'Operator user(back end user) completer'
)
AND rd2.name IN (
'Complaints (Maker)',
'MFS 1344 Help Line',
'MFS 4444 Helpline',
'Operator user(back end user) maker',
'Complaints Checker',
'Operator user(back end user) completer'
);
Query Explain Plan (SQL Developer): (save the file as html and open in browser)
https://drive.google.com/open?id=1KBnhETTzgNLRUh7djyfCN-Wo5QxPZTfb
Important Notes : I am trying to insert the output to a temporary table. If instead i insert this data to a new table using create table as. The same query is working fine :-(
-- previous columns
(
SELECT
o.reason
FROM
cpsmgt.cps_orderhis o
WHERE
o.orderid = t.orderid
) reason_of_task,
-- rest of the query.
Have you tried the following hint?
/*+ INDEX(o IDX_CPS_ORDERHIS_3) USE_NL(o t)*/
Maybe the OPTIMIZER does not choose the right index and choose USE_HASH for the execution plan.

MSSQL 2012 - Why is AVG & TRY_CONVERT not returning the correct value?

I am using MSSQL 2012 and I am trying to use AVG together with TRY_CONVERT on a table column with the following datatype: nvarchar(255), NOT NULL
First before I try to query using AVG & TRY_CONVERT, this is the data that I want to get the AVG value out of using this query:
And this is the results after using AVG and TRY_CONVERT, 0 rows returned.
I also tried to use a subquery then i got 18 row returned, but with value NULL, i skipped out on AVG just to see if i was getting the correct values.. but it seems not, i also included the p.serialnumber column to show that its the correct rows that was returned, its just the value NULL that somehow appears after TRY_CONVERT.
UPDATE!:
When I execute the query below which target data that has a "." separator (qtv2.qtv_qteid = 58 (instead of 63)) , it works! So the issue is the "," separator. Anyone know solution to this??
declare #ProjectSelection nvarchar(10)
set #ProjectSelection = 'C82007588'
SELECT AVG(TRY_CONVERT(numeric(10,5), avgcap))
FROM
(
select qtv2.qtv_result as avgcap
from ProductionOrder PO
left join CustomerOrder co on co.CustomerOrderId=po.customerorderid
left join ProductionOrderProperty pop on pop.ProductionOrderId=po.productionorderid
left join product p on p.ProductionOrderId=po.productionorderid
left join QualityTestValues qtv on qtv.qtv_productid=p.ProductId
left join QualityTestValues qtv2 on qtv2.qtv_productId=p.ProductId
where pop.Value=#ProjectSelection and pop.name = 'project' and po.ProductTypeId = 1
and qtv2.qtv_qteid = 58 and qtv2.qtv_valid = 1 and qtv.qtv_ProductSegmentId = 144 and qtv.qtv_valid = 1
and qtv.qtv_qteid = 51 and qtv.qtv_result = 'J'
group by co.CustomerName, pop.Value, qtv2.qtv_result, p.SerialNumber
) A
Result:
(No column name)
22.200000
How about your compatibility level? A similar question can be found here:
TRY_CONVERT fails on SQL Server 2012
Although your server version is 2012, a lower compatibility level can cause the try_convert to be unavailable for use in your database. You can check this by running the following code in your specific database and afterwards on for instance the master database.
DECLARE #b VARCHAR(10) = '12312'
SELECT TRY_CONVERT(INT,#b)
You can take your first query and do something like this:
SELECT AVG(TRY_CONVERT(numeric(10,5), avgcap))
FROM
(
-- Insert your first query here.
) A
This should give you the average of the numbers.
EDIT
Here is a workable example that should return 24.000000.
SELECT AVG(TRY_CONVERT(numeric(10,5), A))
FROM
(
SELECT '22.5' AS A
UNION
SELECT '23.5' AS A
UNION
SELECT '26.0' AS A
) B
I found out the solution, using TRY_PARSE instead of TRY_CONVERT.
DECLARE #ProjectSelection nvarchar(10)
SET #ProjectSelection = 'C82007588'
SELECT AVG(avgcap) as avgcap
FROM
(
SELECT qtv2.qtv_result, TRY_PARSE( qtv2.qtv_result AS NUMERIC(10,3)) avgcap
FROM ProductionOrder PO
LEFT JOIN CustomerOrder co on co.CustomerOrderId=po.customerorderid
LEFT JOIN ProductionOrderProperty pop on pop.ProductionOrderId=po.productionorderid
LEFT JOIN product p on p.ProductionOrderId=po.productionorderid
LEFT JOIN QualityTestValues qtv on qtv.qtv_productid=p.ProductId
LEFT JOIN QualityTestValues qtv2 on qtv2.qtv_productId=p.ProductId
WHERE pop.Value=#ProjectSelection
AND pop.name = 'project'
AND po.ProductTypeId = 1
AND qtv2.qtv_qteid = 63
AND qtv2.qtv_valid = 1
AND qtv.qtv_ProductSegmentId = 144
AND qtv.qtv_valid = 1
AND qtv.qtv_qteid = 51
AND qtv.qtv_result = 'J'
GROUP BY co.CustomerName, pop.Value, qtv2.qtv_result, p.SerialNumber
) A`
Results:
avgcap
21264.850000

Oracle 9i SQL query - join multiple time the same table

I've a strange behavior with a simple SQL query. I work on Oracle 9i.
I just wanna be sure there is no stupid error in my query. If anyone can tell me what I'm doing wrong. Here's the query :
select p.PARTNUM,
p.N_DATAA, dataa1.ID_DATA as ID_DATAA,
p.N_DATAF, dataf1.ID_DATA as ID_DATAF,
p.N_DATAS, datas1.ID_DATA as ID_DATAS
from PIECES p
left join DATA dataa1 on
dataa1.N_DATA = p.N_DATAA AND
dataa1.REV_DATA = ( select max(dataa2.REV_DATA) from DATA dataa2
where dataa2.N_DATA = p.N_DATAA )
left join DATA dataf1 on
dataf1.N_DATA = p.N_DATAF AND
dataf1.REV_DATA = ( select max(dataf2.REV_DATA) from DATA dataf2
where dataf2.N_DATA = p.N_DATAF )
left join DATA datas1 on
datas1.N_DATA = p.N_DATAS AND
datas1.REV_DATA = ( select max(datas2.REV_DATA) from DATA datas2
where datas2.N_DATA = p.N_DATAS )
where p.PARTNUM='MYPARTNUM';
and here is the result :
"PARTNUM" "N_DATAA" "ID_DATAA" "N_DATAF" "ID_DATAF" "N_DATAS" "ID_DATAS"
"MYPARTNUM" "A23240" "300" "F4130" "398" "S2330" ""
My problem appears on the field ID_DATAS (an ID_DATAS should be returned, I'm sure, see below), it acts as if it ignores the last join and retrieve no data. If I delete the SECOND join, it works perfectly. It seems like if Oracle does not support more than 2 left join... (???)
Here an other example when I switch the two last left join (in this case the problem appears on ID_DATAF) :
select p.PARTNUM,
p.N_DATAA, dataa1.ID_DATA as ID_DATAA,
p.N_DATAF, dataf1.ID_DATA as ID_DATAF,
p.N_DATAS, datas1.ID_DATA as ID_DATAS
from PIECES p
left join DATA dataa1 on
dataa1.N_DATA = p.N_DATAA AND
dataa1.REV_DATA = ( select max(dataa2.REV_DATA) from DATA dataa2
where dataa2.N_DATA = p.N_DATAA )
left join DATA datas1 on
datas1.N_DATA = p.N_DATAS AND
datas1.REV_DATA = ( select max(datas2.REV_DATA) from DATA datas2
where datas2.N_DATA = p.N_DATAS )
left join DATA dataf1 on
dataf1.N_DATA = p.N_DATAF AND
dataf1.REV_DATA = ( select max(dataf2.REV_DATA) from DATA dataf2
where dataf2.N_DATA = p.N_DATAF )
where p.PARTNUM='MYPARTNUM';
and here is the result :
"PARTNUM" "N_DATAA" "ID_DATAA" "N_DATAF" "ID_DATAF" "N_DATAS" "ID_DATAS"
"MYPARTNUM" "A23240" "300" "F4130" "" "S2330" "400"
Thank you for your help :)
EDIT : add fully qualified column names in queries (does not solve my problem)
You are probably experiencing a bug with your old version of Oracle. Oracle 9i was the first version to support ANSI join and came with a few bugs with ANSI-join syntax.
Your query won't run in an up-to-date (11.2) Oracle db (SQLFiddle), you will run into:
ORA-01799: a column may not be outer-joined to a subquery
So the bug in your Oracle version is that this query shouldn't return any result. In any case make sure that you're running the latest patch set. Also it may be a good idea to plan an upgrade, this version is deprecated -- extended support ended 3 years ago!
You'll have to rewrite your query, for instance like this:
SQL> WITH filtered_data AS (
2 SELECT n_data, rev_data, id_data
3 FROM DATA d
4 WHERE rev_data = (SELECT MAX(rev_data)
5 FROM DATA d_in
6 WHERE d_in.n_data = d.n_data)
7 )
8 SELECT p.partnum,
9 p.n_dataa,
10 A.id_data AS id_dataa,
11 p.n_dataf,
12 F.id_data AS id_dataf,
13 p.n_datas,
14 S.id_data AS id_datas
15 FROM pieces p
16 LEFT JOIN filtered_data A ON A.n_data = p.n_dataa
17 LEFT JOIN filtered_data S ON S.n_data = p.n_datas
18 LEFT JOIN filtered_data F ON F.n_data = p.n_dataf
19 WHERE p.PARTNUM = 'MYPARTNUM';
PARTNUM N_DATAA ID_DATAA N_DATAF ID_DATAF N_DATAS ID_DATAS
------------- -------- --------- -------- --------- -------- ---------
MYPARTNUM A23240 300 F4130 398 S2330 400

WHERE in Sql, combining two fast conditions multiplies costs many times

I have a fairly complex sql that returns 2158 rows' id from a table with ~14M rows. I'm using CTEs for simplification.
The WHERE consists of two conditions. If i comment out one of them, the other runs in ~2 second. If i leave them both (separated by OR) the query runs ~100 seconds. The first condition alone needs 1-2 seconds and returns 19 rows, the second condition alone needs 0 seconds and returns 2139 rows.
What can be the reason?
This is the complete SQL:
WITH fpcRepairs AS
(
SELECT FPC_Row = ROW_NUMBER()OVER(PARTITION BY t.SSN_Number ORDER BY t.Received_Date, t.Claim_Creation_Date, t.Repair_Completion_Date, t.Claim_Submitted_Date)
, idData, Repair_Completion_Date, Received_Date, Work_Order, SSN_number, fiMaxActionCode, idModel,ModelName
, SP=(SELECT TOP 1 Reused_Indicator FROM tabDataDetail td INNER JOIN tabSparePart sp ON td.fiSparePart=sp.idSparePart
WHERE td.fiData=t.idData
AND (td.Material_Quantity <> 0)
AND (sp.SparePartName = '1254-3751'))
FROM tabData AS t INNER JOIN
modModel AS m ON t.fiModel = m.idModel
WHERE (m.ModelName = 'LT26i')
AND EXISTS(
SELECT NULL
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON td.fiSparePart = sp.idSparePart
WHERE (td.fiData = t.idData)
AND (td.Material_Quantity <> 0)
AND (sp.SparePartName = '1254-3751')
)
), needToChange AS
(
SELECT idData FROM tabData AS t INNER JOIN
modModel AS m ON t.fiModel = m.idModel
WHERE (m.ModelName = 'LT26i')
AND EXISTS(
SELECT NULL
FROM tabDataDetail AS td
INNER JOIN tabSparePart AS sp ON td.fiSparePart = sp.idSparePart
WHERE (td.fiData = t.idData)
AND (td.Material_Quantity <> 0)
AND (sp.SparePartName IN ('1257-2741','1257-2742','1248-2338','1254-7035','1248-2345','1254-7042'))
)
)
SELECT t.idData
FROM tabData AS t INNER JOIN modModel AS m ON t.fiModel = m.idModel
INNER JOIN needToChange ON t.idData = needToChange.idData -- needs to change FpcAssy
LEFT OUTER JOIN fpcRepairs rep ON t.idData = rep.idData
WHERE
rep.idData IS NOT NULL -- FpcAssy replaced, check if reused was claimed correctly
AND rep.FPC_Row > 1 -- other FpcAssy repair before
AND (
SELECT SP FROM fpcRepairs lastRep
WHERE lastRep.SSN_Number = rep.SSN_Number
AND lastRep.FPC_Row = rep.FPC_Row - 1
) = rep.SP -- same SP, must be rejected(reused+reused or new+new)
OR
rep.idData IS NOT NULL -- FpcAssy replaced, check if reused was claimed correctly
AND rep.FPC_Row = 1 -- no other FpcAssy repair before
AND rep.SP = 0 -- not reused, must be rejected
order by t.idData
Here's the execution plan:
Download: http://www.filedropper.com/exeplanfpc
Try to use UNION ALL of 2 queries separately instead of OR condition.
I've tried it many times and it really helped. I've read about this issue in Art Of SQL .
Read it, you can find many useful information about performance issues.
UPDATE:
Check related questions
UNION ALL vs OR condition in sql server query
http://www.sql-server-performance.com/2011/union-or-sql-server-queries/
Can UNION ALL be faster than JOINs or do my JOINs just suck?
Check Wes's answer
The usage of the OR is probably causing the query optimizer to no longer use an index in the second query.