WHERE IS NULL Not Working in Nested Select - sql

INSERT INTO AutomatedTest_XMLReconciliation(TaskID, TestCaseID, TestInstanceID, XMLHierarchyLevelID, XMLNode, XMLValue_Truth, XMLValue_Test)
(
(SELECT A.TaskID, A.TestCaseID, NULL, A.XMLHierarchyLevelID, A.XMLNode, A.XMLValue_Truth, NULL
FROM AutomatedTest_XMLTruthData A
LEFT JOIN AutomatedTest_Auth B
ON A.TestCaseID = B.TestCaseID
FULL Join AutomatedTest_XMLTestData C
ON B.TestInstanceID = C.TestInstanceID AND A.TruthIdentity = C.TestIdentity AND A.XMLHierarchyLevelID = C.XMLHierarchyLevelID AND A.XMLNode = C.XMLNode AND A.TaskID = C.TaskID
WHERE (B.ReconcileDate IS NULL AND A.TaskID IS NOT NULL)
EXCEPT
(Select A.TaskID, A.TestCaseID, NULL, A.XMLHierarchyLevelID, A.XMLNode, A.XMLValue_Truth, NULL
FROM AutomatedTest_XMLTruthData A
INNER JOIN AutomatedTest_Auth B
ON A.TestCaseID = B.TestCaseID
INNER JOIN AutomatedTest_XMLTestData C
ON B.TestInstanceID = C.TestInstanceID AND A.TruthIdentity = C.TestIdentity AND A.XMLHierarchyLevelID = C.XMLHierarchyLevelID AND A.XMLNode = C.XMLNode AND A.TaskID = C.TaskID)
)
UNION
(SELECT C.TaskID, NULL, C.TestInstanceID, C.XMLHierarchyLevelID, C.XMLNode, NULL, C.XMLValue_Test
FROM AutomatedTest_XMLTruthData A
LEFT JOIN AutomatedTest_Auth B
ON A.TestCaseID = B.TestCaseID
FULL JOIN AutomatedTest_XMLTestData C
ON B.TestInstanceID = C.TestInstanceID AND A.TruthIdentity = C.TestIdentity AND A.XMLHierarchyLevelID = C.XMLHierarchyLevelID AND A.XMLNode = C.XMLNode AND A.TaskID = C.TaskID
WHERE B.ReconcileDate IS NULL AND C.TaskID IS NOT NULL)
EXCEPT
(Select C.TaskID, NULL, C.TestInstanceID, C.XMLHierarchyLevelID, C.XMLNode, NULL, C.XMLValue_Test
FROM AutomatedTest_XMLTruthData A
INNER JOIN AutomatedTest_Auth B
ON A.TestCaseID = B.TestCaseID
INNER JOIN AutomatedTest_XMLTestData C
ON B.TestInstanceID = C.TestInstanceID AND A.TruthIdentity = C.TestIdentity AND A.XMLHierarchyLevelID = C.XMLHierarchyLevelID AND A.XMLNode = C.XMLNode AND A.TaskID = C.TaskID)
))
UPDATE AutomatedTest_Auth
SET ReconcileDate = GETDATE()
WHERE (TestCaseID IN (Select TestCaseID FROM AutomatedTest_DataReconciliation WHERE TestCaseID IS NOT NULL)
OR TestInstanceID IN (Select TestInstanceID FROM AutomatedTest_DataReconciliation WHERE TestInstanceID IS NOT NULL))
AND ReconcileDate IS NULL
So I've got this insert query that is meant to check two tables, one test and one auth, and compare their rows. It matches a TestInstance in the test table with a TestCase in a truth table through the AutomatedTest_Auth table.
Once it is done, it updates the AutomatedTest_Auth table with the GETDATE() stamp to show that the reconciliation process is complete. The insert checks this in the WHEREs to make sure that it does not insert anything that is already inserted by making sure the ReconcileDate IS NULL (it defaults to null on upon a new entry into the AutomatedTest_Auth table).
My problem, however, is that the second "B.Reconcile IS NULL" is not working. Upon running this twice, it will pick up the same rows from AutomatedTest_XMLTestData it picked up the first time and insert them again. (Just a note, there is no PK violation, as the Reconciliation columns could overlap at any time; it has an identity column instead).
Is this an order of operations issue? ... a bug? Any help would be nice.
Also, when I change the B.ReconcileDate IS NULL to IS NOT NULL, the insert swaps, and it will instead insert the same rows from AutomatedTest_XMLTruthData and not AutomatedTest_XMLTestData, so I know the inserts from AutomatedTest_XMLTruthData are correctly recognizing the WHERE clause, and that AutomatedTest_XMLTestData is incorrectly inverting the B.ReconcileData IS NULL to IS NOT NULL.

You are inserting into a table called AutomatedTest_XMLReconciliation
The update where condition looks at a table called AutomatedTest_DataReconciliation which is not referenced elsewhere in your script. Is this correct? I think the Update should be:
UPDATE AUTOMATEDTEST_AUTH
SET RECONCILEDATE = GETDATE()
WHERE ( TESTCASEID IN (SELECT TESTCASEID
FROM AUTOMATEDTEST_XMLRECONCILIATION
WHERE TESTCASEID IS NOT NULL)
OR TESTINSTANCEID IN (SELECT TESTINSTANCEID
FROM AUTOMATEDTEST_XMLRECONCILIATION
WHERE TESTINSTANCEID IS NOT NULL) )
AND RECONCILEDATE IS NULL

Related

SQL Query to apply join on basis of case Condition

I have a requirement where I need to fetch the Dimension Key of Region table on basis of the following preference.
Fetch dimension key on basis of Zipcode of Physical address(PA)
If the first condition is not satisfied that fetch dimension key on basis of the Zip Code of the Mailing address
If the second condition is also not satisfied than fetch the dimension key on basis of the Parish Code of Physical address
Else fetch dimension key on basis of parish Code of Mailing address.
I am trying to use the below query but is giving multiple records since all left joins are getting evaluated. I want that it should not go on the second condition if the first condition is satisfied.
select REGION_DIM_SK, CASE_NUM
from (
select distinct COALESCE(RDIM.REGION_DIM_SK, RDIM1.REGION_DIM_SK, RDIM2.REGION_DIM_SK, RDIM3.REGION_DIM_SK) AS REGION_DIM_SK
, DC.CASE_NUM, ADDR_TYPE_CD
FROM rpt_dm_ee_intg.CASE_PERSON_ADDRESS dc
left join rpt_dm_ee_prsnt.REGION_DIM RDIM on dc.ZIP_CODE = RDIM.ZIP_CODE and RDIM.REGION_EFF_END_DT IS NULL and dc.addr_type_cd='PA' AND dc.EFF_END_DT IS NULL
left join rpt_dm_ee_prsnt.REGION_DIM RDIM1 ON dc.ZIP_CODE = RDIM1.ZIP_CODE AND RDIM1.REGION_EFF_END_DT IS NULL AND dc.addr_type_cd='MA' AND DC.EFF_END_DT IS NULL
left join (
select PARISH_CD, min(REGION_DIM_SK) as REGION_DIM_SK
from rpt_dm_ee_prsnt.REGION_DIM
where REGION_EFF_END_DT is null
group by PARISH_CD
) RDIM2 ON dc.addr_type_cd='PA' and dc.PARISH_CD = RDIM2.PARISH_CD AND DC.EFF_END_DT IS NULL
left join (
select PARISH_CD, min(REGION_DIM_SK) as REGION_DIM_SK
from rpt_dm_ee_prsnt.REGION_DIM
where REGION_EFF_END_DT is null
group by PARISH_CD
) RDIM3 ON dc.addr_type_cd='MA' and dc.PARISH_CD = RDIM3.PARISH_CD AND DC.EFF_END_DT IS NULL
) A
where REGION_DIM_SK is not null
) RD on RD.case_num = rpt_dm_ee_intg.CASE_PERSON_ELIGIBILITY.CASE_NUM
Use multiple left joins. Your query is rather hard to follow -- it has other tables and references not described in the problem.
But the idea is:
select t.*,
coalesce(rpa.dim_key, rm.dim_key, rpap.dim_key, rmp.dim_key) as dim_key
from t left join
dim_region rpa
on t.physical_address_zipcode = rpa.zipcode left join
dim_region rm
on t.mailing_address_zipcode = rm.zipcode and
rpa.zipcode is null left join
dim_region rpap
on t.physical_addresss_parishcode = rpap.parishcode and
rm.zipcode is null left join
dim_region rmp
on t.physical_addresss_parishcode = rmp.parishcode and
rpap.zipcode is null
The trick is to put the conditions in CASE WHEN:
SELECT *
FROM table1 a
JOIN table2 b
ON CASE
WHEN a.code is not null and a.code = b.code THEN 1
WHEN a.type = b.type THEN 1
ELSE 0
END = 1
For your example you can reduce the code to just two joins, it can't be done in one as you are joining two different tables.
SELECT CASE WHEN RDIM.addres IS NULL THEN RDIM2.addres ELSE RDIM.addres
FROM rpt_dm_ee_intg.CASE_PERSON_ADDRESS dc
LEFT JOIN rpt_dm_ee_prsnt.REGION_DIM RDIM ON CASE
WHEN (dc.ZIP_CODE = RDIM.ZIP_CODE
AND RDIM.REGION_EFF_END_DT IS NULL
AND dc.addr_type_cd='PA'
AND dc.EFF_END_DT IS NULL) THEN 1
WHEN (dc.ZIP_CODE = RDIM1.ZIP_CODE
AND RDIM1.REGION_EFF_END_DT IS NULL
AND dc.addr_type_cd='MA'
AND DC.EFF_END_DT IS NULL) THEN 1
ELSE 0
END = 1
LEFT JOIN
(SELECT PARISH_CD,
min(REGION_DIM_SK) AS REGION_DIM_SK
FROM rpt_dm_ee_prsnt.REGION_DIM
WHERE REGION_EFF_END_DT IS NULL
GROUP BY PARISH_CD) RDIM2 ON CASE
WHEN (dc.addr_type_cd='PA'
AND dc.PARISH_CD = RDIM2.PARISH_CD
AND DC.EFF_END_DT IS NULL
AND RDIM.ZIP_CODE IS NULL) THEN 1
WHEN (dc.addr_type_cd='MA'
AND dc.PARISH_CD = RDIM3.PARISH_CD
AND DC.EFF_END_DT IS NULL
AND RDIM.ZIP_CODE IS NULL) THEN 1
ELSE 0
END = 1
edit
If you don't want to have nulls from RDIM2 table if RDIM1 zip code is present the logic could be easily extended to support that. You just need to add AND RDIM.ZIP_CODE IS NULL to CASE WHEN conditions.

T-SQL Full Outer Join (sample provided)

I have some issues getting a full outer join to work in T-SQL. The left outer join part seems to be working okay, but the right outer join doesn't work as expected. Here's some sample data to test this on:
I have a table A with the following columns and data. The row marked with red is the row that cannot be found in table B.
And a second table B with the following columns and data. The rows marked with yellow are the rows that cannot be found in table A.
I am trying to join the tables using the following sql code:
select tableA.klientnr, tableA.uttakstype, tableA.uttaksnr, tableA.vareanr TableAItem,tableB.vareanr tableBitem, tableA.kvantum tableAquantity, tableB.totkvant tableBquantity
from tableA as tableA
full outer join tableB as tableB on tableA.klientnr=tableB.klientnr and tableA.uttakstype=tableB.uttakstype and tableA.uttaksnr=tableB.uttaksnr and tableA.vareanr=tableB.vareanr and tableB.IsDeleted=0
where tableA.UttaksNr=639779 and tableA.IsDeleted=0
The result of the sql is the following image. The row marked in red is the extra row from tableA that does show up, but I can't get the rows from table B to show up
Expected to have 2 extra rows
550 SA 639779 NULL 100059 NULL 0
550 SA 639779 NULL 103040 NULL 14
Later edit:
Would this be correct way to handle the full outer join where there's the header/line type of structure? Or can the query be optimized?
SELECT ISNULL(q1.accountid, q2.accountid) AccountId
,ISNULL(q1.klientnr, q2.klientnr) KlientNr
,ISNULL(q1.tilgangstype, q2.tilgangstype) 'Reception Type'
,ISNULL(q1.tilgangsnr, q2.tilgangsnr) 'Reception No'
,ISNULL(q1.dato, q2.dato) dato
,ISNULL(q1.LevNr, q2.LevNr) LevNr
,ISNULL(q1.Pakkemerke, q2.Pakkemerke) Pakkemerke
,ISNULL(q1.VareANr, q2.VareANr) VareANr
,ISNULL(q1.Ankomstdato,q2.Ankomstdato) 'Arrival Date'
,q1.Antall1
,q1.totkvant1
,q1.Antall2
,q1.totkvant2
,q2.Antall
,q2.totkvant
,q2.AntallTilFrys
,q2.TotKvantTilFrys
,ISNULL(q1.EksternKommentar1,q2.EksternKommentar1) EksternKommentar1
,q2.[Last Upsert]
FROM (
SELECT w700.accountid
,w700.klientnr
,w700.tilgangstype
,w700.tilgangsnr
,w700.dato
,w700.Ankomstdato
,w700.LevNr
,w700.pakkemerke
,w789.VareANr
,sum(IIF(w789.prognosetype = 1, w789.Antall, NULL)) AS Antall1
,sum(IIF(w789.prognosetype = 1, w789.totkvant, NULL)) AS totkvant1
,sum(IIF(w789.prognosetype = 2, w789.Antall, NULL)) AS Antall2
,sum(IIF(w789.prognosetype = 2, w789.totkvant, NULL)) AS totkvant2
,w700.EksternKommentar1
FROM trading.W789Prognosekjopstat AS w789
INNER JOIN trading.W700Tilgangshode AS w700 ON w700.AccountId = w789.AccountId
AND w700.KlientNr = w789.Klientnr
AND w700.Tilgangsnr = w789.Tilgangsnr
AND w700.Tilgangstype = w789.Tilgangstype
AND w700.IsDeleted = 0
WHERE w789.IsDeleted = 0
GROUP BY w700.accountid
,w700.klientnr
,w700.tilgangstype
,w700.tilgangsnr
,w700.dato
,w700.Ankomstdato
,w700.LevNr
,w700.pakkemerke
,w789.VareANr
,w700.EksternKommentar1
) q1
FULL OUTER JOIN (
SELECT w700.accountid
,w700.klientnr
,w700.tilgangstype
,w700.tilgangsnr
,w700.dato
,w700.Ankomstdato
,w700.LevNr
,w700.pakkemerke
,w702.VareANr
,w702.Antall
,w702.TotKvant
,w702.ValPris
,w702.AntallTilFrys
,w702.TotKvantTilFrys
,w700.EksternKommentar1
,(SELECT MAX(LastUpdateDate) FROM (VALUES (w702.createdAt),(w702.updatedAt)) AS UpdateDate(LastUpdateDate)) AS 'Last Upsert'
FROM trading.w702PrognoseKjop w702
INNER JOIN trading.W700Tilgangshode AS w700 ON w700.AccountId = w702.AccountId
AND w700.KlientNr = w702.Klientnr
AND w700.Tilgangsnr = w702.Tilgangsnr
AND w700.Tilgangstype = w702.Tilgangstype
AND w700.IsDeleted = 0
WHERE w702.IsDeleted = 0
) q2 ON q1.accountid = q2.accountid
AND q1.klientnr = q2.klientnr
AND q1.tilgangstype = q2.tilgangstype
AND q1.tilgangsnr = q2.tilgangsnr
AND q1.vareanr = q2.vareanr
WHERE totkvant1 IS NOT NULL
OR totkvant2 IS NOT NULL
OR totkvant IS NOT NULL
Filtering with full join is really tricky. Your where criteria are actually turning the full join into a left join.
You can do what you want by filtering before the join:
select a.klientnr, a.uttakstype, a.uttaksnr, a.vareanr a.tableAitem,
b.vareanr b.tableBitem, a.kvantum a.tableAquantity, b.totkvant b.tableBquantity
from (select a.*
from tableA a
where a.UttaksNr = 639779 and a.IsDeleted = 0
) a full join
(select b.*
from tableB b
where b.IsDeleted = 0
) b
on a.klientnr = b.klientnr and
a.uttakstype= b.uttakstype and
a.uttaksnr = b.uttaksnr and
a.vareanr = b.vareanr;

SQL Server SELECT Sequential Data, Breaking Lines at any Column Diference

I posted a question at MSDN (Brazilian) site. My problem is that I want to make a select at a table that returns a first and last number (from a column) WITHOUT INTERRUPTION and WITHOUT CHANGES on other columns related on the search.
QUESTION UPDATE (2015-04-23)
I've updated my own post on MSDN as on this link. I made a SELECT that would give me almost what i want - but 1 line for the first and 1 line for the final number on each range. It is breaking perfectly, so when the Diag column is O (letter O) means that there is no other number on the range (as O stands for "Only"), so the number would be both initial and final. When the Diag column ins ´F´ is the first number of the range, and due to the ´ORDER BY´ arguments, the last number of that range (as you may guess, with an ´L´ for LAST on the Diag column) is right below it, on the next line. My task now is to create 1 more column on it and then repeated the enNumber field when Diag is O, place the next line ´enNumber´ value when the ´Diag´ column where ´F´ and eliminate all lines with ´L´ on the ´Diag´ column.
SELECT
[EnT].enPrefix,
[EnT].enNumber,
[EnT].enOrder,
[EnT].enDate,
[EnT].enNfe,
[EnT].enClient,
(CASE
WHEN [EnN].enNumber IS NULL THEN
CASE
WHEN [EnP].enNumber IS NULL THEN 'O'
ELSE 'L'
END
ELSE 'F'
END) AS [Diag]
FROM
SerialsDB.dbo.Entries AS [EnT]
LEFT OUTER JOIN SerialsDB.dbo.Entries AS [EnN]
ON ([EnT].enProduct = [EnN].enProduct) AND
([EnN].enNumber = [EnT].enNumber + 1) AND
([EnN].enOrder = [EnT].enOrder) AND
([EnN].enClient = [EnT].enClient) AND
([EnN].enNfe = [EnT].enNfe) AND
([EnN].enDate = [EnT].enDate)
LEFT OUTER JOIN SerialsDB.dbo.Entries AS [EnP]
ON ([EnT].enProduct = [EnP].enProduct) AND
([EnP].enNumber = [EnT].enNumber - 1) AND
([EnP].enOrder = [EnT].enOrder) AND
([EnP].enClient = [EnT].enClient) AND
([EnP].enNfe = [EnT].enNfe) AND
([EnP].enDate = [EnT].enDate)
WHERE
([EnT].enOrder IS NOT NULL) AND
([EnT].enClient IS NOT NULL) AND
(([EnP].enNumber IS NULL) OR
([EnN].enNumber IS NULL))
ORDER BY
[EnT].enOrder ASC,
[EnT].enDate ASC,
[EnT].enNfe ASC,
[EnT].enPrefix ASC,
[EnT].enNumber ASC
Help!
This is not going to be a simple query using a GROUP BY.
For simplicity and to show the basic idea I assume Entries table just got two columns: enNumber and enProduct. You can add all other columns and criteria later.
CREATE TABLE [Entries](
[enNumber] [int] NOT NULL,
[enProduct] [int] NOT NULL,
CONSTRAINT [PK_Entries] PRIMARY KEY CLUSTERED ([enNumber] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT INTO [Entries] VALUES (1000309,2768)
INSERT INTO [Entries] VALUES (1000310,2768)
INSERT INTO [Entries] VALUES (1000311,2768)
INSERT INTO [Entries] VALUES (1000312,2768)
INSERT INTO [Entries] VALUES (1000313,2768)
INSERT INTO [Entries] VALUES (1000314,2768)
INSERT INTO [Entries] VALUES (1000315,2768)
INSERT INTO [Entries] VALUES (1000316,2768)
INSERT INTO [Entries] VALUES (1000317,2768)
/* interrupt */
INSERT INTO [Entries] VALUES (1001388,3328)
INSERT INTO [Entries] VALUES (1001389,3328)
INSERT INTO [Entries] VALUES (1001390,3328)
INSERT INTO [Entries] VALUES (1001391,3328)
INSERT INTO [Entries] VALUES (1001392,3328)
/* change */
INSERT INTO [Entries] VALUES (1001393,3743)
INSERT INTO [Entries] VALUES (1001394,3743)
INSERT INTO [Entries] VALUES (1001395,3743)
INSERT INTO [Entries] VALUES (1001396,3743)
/* change */
INSERT INTO [Entries] VALUES (1001397,3328)
INSERT INTO [Entries] VALUES (1001398,3328)
INSERT INTO [Entries] VALUES (1001399,3328)
INSERT INTO [Entries] VALUES (1001400,3328)
/* interrupt */
INSERT INTO [Entries] VALUES (1003000,2768)
/* change */
INSERT INTO [Entries] VALUES (1003001,3328)
INSERT INTO [Entries] VALUES (1003002,3328)
INSERT INTO [Entries] VALUES (1003003,3328)
GO
Create two views, one of them giving all the records that act as the initial of a group and another view for the finals.
A record is an initial/final record if the previous/next enNumber does not exist (an interrupt) or has different values (a change).
CREATE VIEW [Initials] AS
SELECT E.enNumber
FROM Entries E
LEFT JOIN Entries E2 on E2.enNumber = E.enNumber - 1
AND E2.enProduct= E.enProduct
WHERE E2.enNumber IS NULL
GO
CREATE VIEW [Finals] AS
SELECT E.enNumber
FROM Entries E
LEFT JOIN Entries E2 on E2.enNumber = E.enNumber + 1
AND E2.enProduct= E.enProduct
WHERE E2.enNumber IS NULL
GO
Each record in Initials has a counterpart in Finals with an enNumber equal or greater than its enNumber.
SELECT i.enNumber AS Initial, E.enProduct
FROM Initials i
LEFT JOIN Entries E ON E.enNumber = i.enNumber
SELECT f.enNumber AS Final, E.enProduct
FROM Finals f
LEFT JOIN Entries E ON E.enNumber = f.enNumber
Initial enProduct
1000309 2768
1001388 3328
1001393 3743
1001397 3328
1003000 2768
1003001 3328
Final enProduct
1000317 2768
1001392 3328
1001396 3743
1001400 3328
1003000 2768
1003003 3328
You can combine these two views in different ways to achieve the desired results:
SELECT i.enNumber AS initial, MIN(f.enNumber) AS final, E.enProduct
FROM Initials i
LEFT JOIN finals f ON f.enNumber >= i.enNumber
LEFT JOIN Entries E ON E.enNumber = i.enNumber
GROUP BY i.enNumber, E.enProduct
ORDER BY i.enNumber
initial final enProduct
1000309 1000317 2768
1001388 1001392 3328
1001393 1001396 3743
1001397 1001400 3328
1003000 1003000 2768
1003001 1003003 3328
I think you need to do this with subquery. In the subquery, you will get the min and max values and include the columns you want to sort by. In the main query, you will select all columns. See the following link for details:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
Section "Selecting the one maximum row from each group"
I've wrote a query and got the results i was trying to find. I still don't like it very much as i think it will have a big cost on the database to run it, and i'd like to find one simpler. But anyway, the "problem" it self is resolved.
The resulting query is writen as follows:
SELECT
[Pre].[pfPrefix],
[Pro].[prId],
[Pro].[prName],
(CASE
WHEN [EnP].[enNumber] IS NULL THEN [EnT].[enNumber]
ELSE
(SELECT TOP 1
[iET].[enNumber]
FROM
[SerialsDB].[dbo].[Entries] AS [iET]
LEFT OUTER JOIN [SerialsDB].[dbo].[Entries] AS [iEP]
ON (([iEP].[enProduct] IS NULL AND [iET].[enProduct] IS NULL) OR
([iEP].[enProduct] = [iET].[enProduct])) AND
(([iEP].[enOrder] IS NULL AND [iET].[enOrder] IS NULL) OR
([iEP].[enOrder] = [iET].[enOrder])) AND
(([iEP].[enClient] IS NULL AND [iET].[enClient] IS NULL) OR
([iEP].[enClient] = [iET].[enClient])) AND
(([iEP].[enNfe] IS NULL AND [iET].[enNfe] IS NULL) OR
([iEP].[enNfe] = [iET].[enNfe])) AND
(([iEP].[enDate] IS NULL AND [iET].[enDate] IS NULL) OR
([iEP].[enDate] = [iET].[enDate])) AND
(([iEP].[enAuth] IS NULL AND [iET].[enAuth] IS NULL) OR
([iEP].[enAuth] = [iET].[enAuth])) AND
(([iEP].[enStatus] IS NULL AND [iET].[enStatus] IS NULL) OR
([iEP].[enStatus] = [iET].[enStatus])) AND
([iEP].[enNumber] = ([iET].[enNumber] - 1))
WHERE
(([iET].[enProduct] IS NULL AND [EnT].[enProduct] IS NULL) OR
([iET].[enProduct] = [EnT].[enProduct])) AND
(([iET].[enOrder] IS NULL AND [EnT].[enOrder] IS NULL) OR
([iET].[enOrder] = [EnT].[enOrder])) AND
(([iET].[enDate] IS NULL AND [EnT].[enDate] IS NULL) OR
([iET].[enDate] = [EnT].[enDate])) AND
(([iET].[enClient] IS NULL AND [EnT].[enClient] IS NULL) OR
([iET].[enClient] = [EnT].[enClient])) AND
(([iET].[enNfe] IS NULL AND [EnT].[enNfe] IS NULL) OR
([iET].[enNfe] = [EnT].[enNfe])) AND
(([iET].[enAuth] IS NULL AND [EnT].[enAuth] IS NULL) OR
([iET].[enAuth] = [EnT].[enAuth])) AND
(([iET].[enStatus] IS NULL AND [EnT].[enStatus] IS NULL) OR
([iET].[enStatus] = [EnT].[enStatus])) AND
([iET].[enNumber] <= [EnP].[enNumber]) AND
([iEP].[enNumber] IS NULL)
ORDER BY
[iET].[enNumber] DESC)
END) AS [Initial],
[EnT].[enNumber] AS [Final],
[EnT].[enOrder],
[EnT].[enDate],
[EnT].[enNfe],
[EnT].[enClient],
[Cli].[clGroup],
[EnT].[enAuth]
FROM
[SerialsDB].[dbo].Entries AS [EnT]
LEFT OUTER JOIN [SerialsDB].[dbo].[Entries] AS [EnN]
ON ([EnN].[enProduct] = [EnT].[enProduct]) AND
([EnN].[enOrder] = [EnT].[enOrder]) AND
([EnN].[enClient] = [EnT].[enClient]) AND
(([EnN].[enNfe] IS NULL AND [EnT].[enNfe] IS NULL) OR
([EnN].[enNfe] = [EnT].[enNfe])) AND
([EnN].[enDate] = [EnT].[enDate]) AND
([EnN].[enStatus] = [EnT].[enStatus]) AND
([EnN].[enAuth] = [EnT].[enAuth]) AND
([EnN].[enNumber] = ([EnT].[enNumber] + 1))
LEFT OUTER JOIN [SerialsDB].[dbo].[Entries] AS [EnP]
ON ([EnP].[enProduct] = [EnT].[enProduct]) AND
([EnP].[enOrder] = [EnT].[enOrder]) AND
([EnP].[enClient] = [EnT].[enClient]) AND
(([EnP].[enNfe] IS NULL AND [EnT].[enNfe] IS NULL) OR
([EnP].[enNfe] = [EnT].[enNfe])) AND
([EnP].[enDate] = [EnT].[enDate]) AND
([EnP].[enStatus] = [EnT].[enStatus]) AND
([EnP].[enAuth] = [EnT].[enAuth]) AND
([EnP].[enNumber] = ([EnT].[enNumber] - 1))
LEFT OUTER JOIN [SerialsDB].[dbo].[Prefixes] AS [Pre]
ON ([EnT].[enPrefix] = [Pre].[pfId])
LEFT OUTER JOIN [SerialsDB].[dbo].[Products] AS [Pro]
ON ([EnT].[enProduct] = [Pro].[prId])
LEFT OUTER JOIN [SerialsDB].[dbo].[Clients] AS [Cli]
ON ([EnT].[enClient] = [Cli].[clId])
WHERE
([EnT].[enOrder] IS NOT NULL) AND
([EnT].[enClient] IS NOT NULL) AND
([EnN].[enNumber] IS NULL) AND
([EnT].[enStatus] = 4) AND
([EnT].[enAuth] IS NOT NULL)
Thank you Amir for the great inputs, and for Stamen for the suggestion.

Inadvertent cross join occurring in SQL merge

I have two tables that I would like to join with the following columns:
Tables: #IndexDecomposition; Constituent.
Rows: Identifier; CUSIP; ISIN; SEDOL.
This is all part of a larger MERGE statement, and now I think that the cross join is happening on the INSERT statement:
MERGE indexdecomp.ConstituentWeighting targ
USING (#IndexConstituents src
INNER JOIN indexDecomp.Constituent c WITH (NOLOCK) on
((c.Identifier = src.Identifier) OR (c.Identifier IS NULL AND src.Identifier IS NULL))
AND ((c.CUSIP = src.CUSIP) OR (c.CUSIP IS NULL AND src.CUSIP IS NULL))
AND ((c.ISIN = src.ISIN) OR (c.ISIN IS NULL AND src.ISIN IS NULL))
AND ((c.SEDOL = src.SEDOL) OR (c.SEDOL IS NULL AND src.SEDOL IS NULL)))
ON ( targ.ConstituentId = c.Id
AND targ.AsOfDate = src.Date
AND ((targ.Weighting = src.Weighting) OR (targ.Weighting IS NULL AND src.Weighting IS NULL))
AND ((targ.TotalSharesHeld = src.TotalSharesHeld) OR (targ.TotalSharesHeld IS NULL AND src.TotalSharesHeld IS NULL))
AND ((targ.SharesOutstanding = src.SharesOutstanding) OR (targ.SharesOutstanding IS NULL AND src.SharesOutstanding IS NULL))
AND ((targ.NotionalValue = src.NotionalValue) OR (targ.NotionalValue IS NULL AND src.NotionalValue IS NULL))
AND ((targ.MarketValue = src.MarketValue) OR (targ.MarketValue IS NULL AND src.MarketValue IS NULL))
AND ((targ.MarketCap = src.MarketCap) OR (targ.MarketCap IS NULL AND src.MarketCap IS NULL))
AND ((targ.LastTrade = src.LastTrade) OR (targ.LastTrade IS NULL AND src.LastTrade IS NULL))
AND ((targ.Earnings = src.Earnings) OR (targ.Earnings IS NULL AND src.Earnings IS NULL))
AND ((targ.PeRatio = src.PeRatio) OR (targ.PeRatio IS NULL AND src.PeRatio IS NULL))
AND ((targ.Face = src.Face) OR (targ.Face IS NULL AND src.Face IS NULL)))
WHEN NOT MATCHED BY TARGET THEN
INSERT (
ConstituentID
,AsOfDate
,Weighting
,TotalSharesHeld
,SharesOutstanding
,NotionalValue
,MarketValue
,MarketCap
,LastTrade
,Earnings
,PeRatio
,Face
,ModifiedBy
,ModifiedDate
,CreatedBy
,CreatedDate
)
VALUES (
c.Id
,src.Date
,src.Weighting
,src.TotalSharesHeld
,src.SharesOutstanding
,src.NotionalValue
,src.MarketValue
,src.MarketCap
,src.LastTrade
,src.Earnings
,src.PeRatio
,src.Face
,'user'
,getdate()
,'user'
,getdate()
)
;
I think the only problem with your latest attempt is that it does not weed out combinations of all nulls (i.e. false positives where all four IDs are null). You can fix it by requiring that at least one of the four identifiers mus be non-null, like this:
SELECT *
FROM xTradeCapture.staging.IndexDecomposition src
INNER JOIN indexDecomp.Constituent c WITH (NOLOCK) on
(((c.Identifier = src.Identifier) OR (c.Identifier IS NULL AND src.Identifier IS NULL))
AND ((c.CUSIP = src.CUSIP) OR (c.CUSIP IS NULL AND src.CUSIP IS NULL))
AND ((c.ISIN = src.ISIN) OR (c.ISIN IS NULL AND src.ISIN IS NULL))
AND ((c.SEDOL = src.SEDOL) OR (c.SEDOL IS NULL AND src.SEDOL IS NULL))
AND (c.Identifier IS NOT NULL OR c.CUSIP IS NOT NULL OR c.ISIN IS NOT NULL OR c.SEDOL IS NOT NULL))
The second code snippet of yours is correct. The optimizer recognizes this pattern and converts it into an equi-join. So you don't get a cartesian product.
You could also use ISNULL if you have dummy values you know are not in the tables them selves. The example below assumes integers for Identifier & CUSIP and varchar for ISIN and SEDOL...
SELECT *
FROM xTradeCapture.staging.IndexDecomposition src
INNER JOIN indexDecomp.Constituent c WITH (NOLOCK) on
ISNULL(c.Identifier,-1) = ISNULL(src.Identifier,-1)
AND ISNULL(c.CUSIP,-1) = ISNULL(src.CUSIP,-1)
AND ISNULL(c.ISIN,'ABC') = ISNULL(src.ISIN,'ABC')
AND ISNULL(c.SEDOL,'ABC') = ISNULL(src.SEDOL,'ABC')

SQL SP runs Slow

Hi
I am using an SP which takes 7 minutes in a server which has 7336 recrds
and 6seconds in another server which has 3500 records.
Can anybody help me to know why is it happening?
Thanks,
-Divya
THE SP:
SELECT WORKSHEET_ID
FROM PERSON PER
INNER JOIN PERSON EMPLEE
ON EMPLEE.PERSON_ID = PER.PERSON_ID
AND
dbo.FN_CHECKRPTSECURITY(EMPLEE.PERSON_ID, #p_SEC_ACCOUNT_ID) > 0
LEFT JOIN SEARCH_ASSIGNMENT_VW PERSON_ASGN
ON PERSON_ASGN.ASSIGNMENT_ID =
dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
LEFT JOIN LOOKUP EMPLEE_ASGN_STAT
ON EMPLEE_ASGN_STAT.TYPE_ = 'ASSIGNMMENT_STATUS_CODE'
AND EMPLEE_ASGN_STAT.CODE = PERSON_ASGN.ASGN_STAT_CODE
INNER JOIN
(SELECT w1.ASSIGNMENT_ID, w1.WORKSHEET_ID, w1.EFFECTIVE_DATE, w1.APPROVED_BY, w3.CREATED_BY
FROM WORKSHEET_PAYROLL_VW w1
INNER JOIN WORKSHEET w3
ON w3.WORKSHEET_ID = w1.WORKSHEET_ID
WHERE w1.EFFECTIVE_DATE = CASE
WHEN #p_MOST_RECENT_ONLY = 'Y'
THEN (SELECT MAX(w2.EFFECTIVE_DATE)
FROM WORKSHEET_PAYROLL_VW w2
WHERE w1.ASSIGNMENT_ID = w2.ASSIGNMENT_ID
AND (ISNULL(#p_WKS_EFFECTIVE_DATE,w2.EFFECTIVE_DATE) =w2.EFFECTIVE_DATE))
ELSE ISNULL(#p_WKS_EFFECTIVE_DATE,w1.EFFECTIVE_DATE)
END
)
PERSON_WKS
ON PERSON_WKS.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
INNER JOIN
(SELECT ASSIGNMENT_ID, VALUE
FROM ASSIGNMENT_HISTORY AH
WHERE FIELD_NAME ='HOME PAYROLL GROUP'
AND EFFECTIVE_DATE = (SELECT MAX(EFFECTIVE_DATE)
FROM ASSIGNMENT_HISTORY
WHERE ASSIGNMENT_ID = AH.ASSIGNMENT_ID
AND EFFECTIVE_DATE <=getDate()
AND FIELD_NAME = 'HOME PAYROLL GROUP')
)HOME_PAYROLL
ON HOME_PAYROLL.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
WHERE
(#p_SELECTED_PERSON_ONLY = 'N' OR EMPLEE.PERSON_ID = #p_PERSON_ID)
AND
(#p_ASGN_STAT_CODE IS NULL OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,1,1)
OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,2,1))
AND
(#p_POLICY_ID IS NULL OR PERSON_ASGN.PROGRAM_CODE = #p_POLICY_ID)
AND
(#p_HOME_COUNTRY_ID IS NULL OR PERSON_ASGN.HOMECOUNTRYID=#p_HOME_COUNTRY_ID)
AND
(#p_HOME_CITY_ID IS NULL OR PERSON_ASGN.HOMECITYID=#p_HOME_CITY_ID )
AND
(#p_HOME_COMPANY_ID IS NULL OR PERSON_ASGN.HOMEBUSINESSID=#p_HOME_COMPANY_ID )
AND
(#p_HOME_DIVISION_ID IS NULL OR PERSON_ASGN.HOMECOMPONENTID=#p_HOME_DIVISION_ID )
AND
(#p_HOST_COUNTRY_ID IS NULL OR PERSON_ASGN.HOSTCOUNTRYID=#p_HOST_COUNTRY_ID )
AND
(#p_HOST_CITY_ID IS NULL OR PERSON_ASGN.HOSTCITYID=#p_HOST_CITY_ID )
AND
(#p_HOST_COMPANY_ID IS NULL OR PERSON_ASGN.HOSTBUSINESSID=#p_HOST_COMPANY_ID )
AND
(#p_HOST_DIVISION_ID IS NULL OR PERSON_ASGN.HOSTCOMPONENTID=#p_HOST_DIVISION_ID )
AND
(#p_CREATED_BY IS NULL OR PERSON_WKS.CREATED_BY=#p_CREATED_BY )
AND
(#p_APPROVED_BY IS NULL OR PERSON_WKS.APPROVED_BY=#p_APPROVED_BY )
AND
(#p_payroll_code IS NULL OR HOME_PAYROLL.VALUE=#p_payroll_code )
ORDER BY PER.LAST_NAME ASC,
PER.FIRST_NAME ASC,
PERSON_WKS.EFFECTIVE_DATE DESC
The Function in the 5th line is the one which is running slow. rest of the part is running in 4secs
The FUNCTION:
BEGIN
DECLARE
#v_ASGN_COUNT INT,
#v_RESULT INT
SELECT #v_ASGN_COUNT = COUNT(ASSIGNMENT_ID) --to find out if this employee has any assignment
FROM ASSIGNMENT
WHERE EXPATRIATE_PERSON_ID = #p_PERSON_ID AND
ASGN_STAT_CODE IN ('PD','A','I')
IF(#v_ASGN_COUNT > 0) --yes assignment, check against SECURITY_ASSIGNMENT_VW
BEGIN
SELECT #v_RESULT = COUNT(ASSIGNMENT_ID)
FROM SECURITY_ASSIGNMENT_VW
WHERE SEC_ACCOUNT_ID = #p_SEC_ACCOUNT_ID AND
ASSIGNMENT_ID IN (SELECT ASSIGNMENT_ID
FROM ASSIGNMENT
WHERE EXPATRIATE_PERSON_ID = #p_PERSON_ID AND
ASGN_STAT_CODE IN ('PD','A','I'))
END
ELSE --no assignment, so check against SECURITY_PERSON_VW
BEGIN
SELECT #v_RESULT = COUNT(PERSON_ID)
FROM SECURITY_PERSON_VW
WHERE SEC_ACCOUNT_ID = #p_SEC_ACCOUNT_ID AND
PERSON_ID = #p_PERSON_ID
END
RETURN #v_RESULT
END
Do the schemas match exactly... in particular check for missing indexes.
Well to begin with you have scalar functions which will run significantly slower as the number of records increase becasue they process row-by-agonizing-row. Not only that you've used the functions in joins which is a horrible practice if you need performance. You have a bunch of OR conditions which tend to slowness. And while it is too hard to actually read the code you posted (please try to format and only use all caps for keywords), I would suspect that some of those conditions are not sargable.
To know what is actually happening check the Execution plan (SQL Server) or Explain Plan (mySQL and others I think) or the equivalent feature in your database. Likely you wil find table scans which of course are going to get significantly slower as the number of records increases.
You may also have a problem with parameter sniffing. Please google to see how to fix that.
One improvement would be to make sure that dbo.FN_GETRPTSSIGNMENTID only gets executed once.
Currently, it gets executed three times.
You can replace two of those calls by joining to the field of the (one) remaing call.
Something like
SELECT WORKSHEET_ID
FROM PERSON PER
INNER JOIN PERSON EMPLEE ON EMPLEE.PERSON_ID = PER.PERSON_ID AND dbo.FN_CHECKRPTSECURITY(EMPLEE.PERSON_ID, #p_SEC_ACCOUNT_ID) > 0
INNER JOIN (
SELECT w1.ASSIGNMENT_ID
, w1.WORKSHEET_ID
, w1.EFFECTIVE_DATE
, w1.APPROVED_BY
, w3.CREATED_BY
FROM WORKSHEET_PAYROLL_VW w1
INNER JOIN WORKSHEET w3 ON w3.WORKSHEET_ID = w1.WORKSHEET_ID
WHERE w1.EFFECTIVE_DATE =
CASE WHEN #p_MOST_RECENT_ONLY = 'Y'
THEN (
SELECT MAX(w2.EFFECTIVE_DATE)
FROM WORKSHEET_PAYROLL_VW w2
WHERE w1.ASSIGNMENT_ID = w2.ASSIGNMENT_ID AND (ISNULL(#p_WKS_EFFECTIVE_DATE,w2.EFFECTIVE_DATE) = w2.EFFECTIVE_DATE)
)
ELSE ISNULL(#p_WKS_EFFECTIVE_DATE,w1.EFFECTIVE_DATE)
END
) PERSON_WKS ON PERSON_WKS.ASSIGNMENT_ID = dbo.FN_GETRPTASSIGNMENTID(EMPLEE.PERSON_ID)
INNER JOIN (
SELECT ASSIGNMENT_ID
, VALUE
FROM ASSIGNMENT_HISTORY AH
WHERE FIELD_NAME ='HOME PAYROLL GROUP'
AND EFFECTIVE_DATE = (
SELECT MAX(EFFECTIVE_DATE)
FROM ASSIGNMENT_HISTORY
WHERE ASSIGNMENT_ID = AH.ASSIGNMENT_ID
AND EFFECTIVE_DATE <=getDate()
AND FIELD_NAME = 'HOME PAYROLL GROUP'
)
LEFT JOIN SEARCH_ASSIGNMENT_VW PERSON_ASGN ON PERSON_ASGN.ASSIGNMENT_ID = PERSON_WKS.ASSIGNMENT_ID
LEFT JOIN LOOKUP EMPLEE_ASGN_STAT ON EMPLEE_ASGN_STAT.TYPE_ = 'ASSIGNMMENT_STATUS_CODE' AND EMPLEE_ASGN_STAT.CODE = PERSON_ASGN.ASGN_STAT_CODE
) HOME_PAYROLL ON HOME_PAYROLL.ASSIGNMENT_ID = PERSON_WKS.ASSIGNMENT_ID
WHERE (#p_SELECTED_PERSON_ONLY = 'N' OR EMPLEE.PERSON_ID = #p_PERSON_ID)
AND (#p_ASGN_STAT_CODE IS NULL OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,1,1) OR PERSON_ASGN.ASGN_STAT_CODE = SUBSTRING(#p_ASGN_STAT_CODE,2,1))
AND (#p_POLICY_ID IS NULL OR PERSON_ASGN.PROGRAM_CODE = #p_POLICY_ID)
AND (#p_HOME_COUNTRY_ID IS NULL OR PERSON_ASGN.HOMECOUNTRYID=#p_HOME_COUNTRY_ID)
AND (#p_HOME_CITY_ID IS NULL OR PERSON_ASGN.HOMECITYID=#p_HOME_CITY_ID )
AND (#p_HOME_COMPANY_ID IS NULL OR PERSON_ASGN.HOMEBUSINESSID=#p_HOME_COMPANY_ID )
AND (#p_HOME_DIVISION_ID IS NULL OR PERSON_ASGN.HOMECOMPONENTID=#p_HOME_DIVISION_ID )
AND (#p_HOST_COUNTRY_ID IS NULL OR PERSON_ASGN.HOSTCOUNTRYID=#p_HOST_COUNTRY_ID )
AND (#p_HOST_CITY_ID IS NULL OR PERSON_ASGN.HOSTCITYID=#p_HOST_CITY_ID )
AND (#p_HOST_COMPANY_ID IS NULL OR PERSON_ASGN.HOSTBUSINESSID=#p_HOST_COMPANY_ID )
AND (#p_HOST_DIVISION_ID IS NULL OR PERSON_ASGN.HOSTCOMPONENTID=#p_HOST_DIVISION_ID )
AND (#p_CREATED_BY IS NULL OR PERSON_WKS.CREATED_BY=#p_CREATED_BY )
AND (#p_APPROVED_BY IS NULL OR PERSON_WKS.APPROVED_BY=#p_APPROVED_BY )
AND (#p_payroll_code IS NULL OR HOME_PAYROLL.VALUE=#p_payroll_code )
ORDER BY
PER.LAST_NAME ASC
, PER.FIRST_NAME ASC
, PERSON_WKS.EFFECTIVE_DATE DESC