SQL Server : FULL OUTER JOIN unusual behavior - sql

I have 2 tables. I want to get the records from both the table using FULL OUTER JOIN while filtering out some data from one of the tables.
14026 - Total number of common records.
8428 - unique records in table 1
1512 - unique records in table 2.
The total records that I should get are 23966. However, the following queries return different results.
Query 1 -
SELECT DISTINCT pu.id,
vm.id
FROM table1 vm
FULL OUTER JOIN (SELECT DISTINCT pu.id
FROM table2 pu
WHERE pu.column1 = 'filter1'
AND pu.column2 = 'filter2') pu ON vm.id = pu.id;
Output - 23966 rows (expected).
Query 2 -
SELECT DISTINCT pu.id,
vm.id
FROM table1 vm
FULL OUTER JOIN table2 pu ON vm.id = pu.id AND pu.column1 = 'filter1' AND pu.column2 = 'filter2';
Output - 48804 rows.
Query 3 -
SELECT DISTINCT pu.id,
vm.id
FROM table1 vm
FULL OUTER JOIN table2 pu ON vm.id = pu.id
WHERE (pu.column1 = 'filter1' AND pu.column2 = 'filter2')
OR (pu.column1 IS NULL AND pu.column2 IS NULL);
Output - 21830.
According to my understanding at least the third query should also give me the same result as query 1. Can someone explain me how SQL Server is treating these 3 queries?

Related

Oracle inner join give wrong result set

When I execute this query it gives a 10 result set .
select * from OA_SERVICE_REQUESTS WHERE
OA_SERVICE_REQUESTS.CUSREG_ID=4
But when I join with other table with to get more information, I use 2 inner join because this is 2 foreign key from ELVM_SMUNT_CUS table it gives me 120 results
select * from OA_SERVICE_REQUESTS
inner join ELVM_SMUNT_CUS T1 on OA_SERVICE_REQUESTS.DIVCOD = T1.DIVCOD
inner join ELVM_SMUNT_CUS T2 on OA_SERVICE_REQUESTS.UNTNUM = T2.UNTNUM
WHERE OA_SERVICE_REQUESTS.CUSREG_ID=4
Try to combine them together :
select * from OA_SERVICE_REQUESTS R
inner join ELVM_SMUNT_CUS T1 on ( R.DIVCOD = T1.DIVCOD
and R.UNTNUM = T1.UNTNUM )
where R.CUSREG_ID=4;
for your query not to produce cross-product results.
Probably, you have 12 matching records for R.DIVCOD = T1.DIVCOD, and 10 matching records for R.UNTNUM = T1.UNTNUM for R.CUSREG_ID=4, by combining the result set by an and you can have 10results at the same time, but may yield 120 occurences by 12 times 10, if conditions are taken apart by more joins.

ORACLE SQL - Get limited rows with maximum values in a column with rownum but without a subquery

I have a table in Oracle DB which consists of products and stock. I want to get a limited number of products in output (say 10 products) with maximum stock. There are also other conditions that I would check which involves inner join with multiple tables.
This query randomly selects 10 products from the table then sorts it, so its not helpful:
Select prod_code, stock from producttable where rownum < 10
--and lots of other conditions
order by stock desc
I searched and found this below method. But this runs forever because the inner query is a full table output:
Select * from (Select prod_code, stock from producttable where
-- lots of other conditions
order by stock desc) where rownum < 10
Can someone please help me find a way to do this accurately and efficiently ?
Following is the query used -
SELECT * from (SELECT
wbob.p1
FROM t1 wbob
Inner join t2 wboc on wboc.p2 = wbob.p2
Inner join t3 wboa on wboa.p2 = wbob.p2
Inner join t4 mfa on mfa.p3 = wbob.p4
Left outer join t5 mfb on mfb.p3 = wbob.p4
Inner join t6 mfc on mfc.p3 = wbob.p4
Inner join t7 mfd on mfd.p3 = wbob.p4
Inner join t8 mfg on mfg.p3 = wbob.p4
Inner join t9 sta on sta.p5 = wbob.p4
Inner join t10 stb on stb.p6 = sta.p6
Inner join t11 stc on stc.p7 = stb.p7
WHERE
wboa.stock > '0'
and wboa.p8 in ('14','198')
and wboc.p9 = '187'
and mfd.p10 > 0
and stb.p11 > 0
and trim(mfa.p12) = 'ACT'
and mfa.p13 = 'N'
and trim(stc.p7) = '3333'
and mfc.p14 = 11
and mfc.p15 = 3333
and mfg.p16 = 1
and mfc.p17 = 'Y'
and mfd.p18 = 'N'
and mfa.p19 = 'W'
and wbob.p1 NOT IN (Select wbob1.p1
from t1 wbob1
inner join t3 wboa1 ON wboa1.p2 = wbob1.p2
where wboa1.stock > '0'
and wboa1.p8 NOT IN ('14','198'))
and (wbob.p4 NOT IN (Select mfb7.p3 from t5 mfb7) OR wbob.p4 IN (Select mfb8.p3 from t5 mfb8
where mfb8.p20 = 0))
ORDER BY stb.p11 DESC) where rownum < 10
Explain plan
You can do this in 12c without a subquery using fetch first n rows only
Select prod_code, stock
from producttable
where ...
--and lots of other conditions
order by stock desc
fetch first 10 rows only
However, this will not solve the problem you are complaining about which is the performance of the query and how the inner query is a full table output. This is actually necessary and this solution will do the same. In order to sort stock to get the top stock items, the db will have to look at and sort all the possible rows. How else can you get the top items without looking at all of them? There might be ways to improve this, like an index on the stock value, but I wouldn't recommend that without knowing detail your data model.
You need a subquery:
select p.*
from (Select prod_code, stock
from producttable
order by stock desc
) p
where rownum < 10;
For performance, you want an index on producttable(stock, prod_code). The subquery isn't causing the performance issue; the lack of index is.

Query with combined WHERE clause is slower than two individual WHERE clauses

I'm having a performance problem with a SQL query that is generated by a .NET application.
Basically what the query is doing is:
(query1) left join (query2) right join (queries3 to 30) WHERE (query1.ID IS NULL) OR (query3.ID IS NULL AND query4.ID IS NULL AND… queryN.ID IS NULL)
When the query only does WHERE A (query1.ID) the query is fast.
When the query only does WHERE B (query3 to 30) the query is fast
When A and B are a combined WHERE clause with an OR, the query is
very slow.
I'm looking for a way to optimize this query without variables or stored procedures.
The query:
SELECT DISTINCT [Table0].[FIELD]
FROM /*8*/ ([Table0] AS [Table0]
INNER JOIN
[XTABLE] AS [XTABLE0]
ON [Table0].ID = [XTABLE0].ID1
AND [XTABLE0].ID3 = 52)
RIGHT OUTER /*10*/ JOIN
[Table1] AS [Table1]
/*21*/ /*11*/ ON [XTABLE0].ID2 = [Table1].ID
AND [XTABLE0].ID3 = 52
LEFT OUTER JOIN
([XTABLE] AS [XTABLE1]
INNER JOIN
[Table2] AS [Table2]
ON [XTABLE1].ID1 = [Table2].ID
AND [XTABLE1].ID3 = 19
/*20a*/ INNER JOIN
[XTABLE] AS [XTABLE2]
ON [Table2].ID = [XTABLE2].ID1
AND [XTABLE2].ID3 = 8
INNER JOIN
[Table3] AS [Table3]
ON [XTABLE2].ID2 = [Table3].ID
AND [XTABLE2].ID3 = 8/*22*/ )
ON [Table1].ID = [XTABLE1].ID2
AND [XTABLE1].ID3 = 19
/*26 */ LEFT OUTER JOIN
([XTABLE] AS [XTABLE3]
... and tens of similar INNER JOIN blocks
WHERE (/*13*/ [XTABLE0].ID IS NULL)
OR (/*25*/ [XTABLE1].ID IS NULL
AND /*27b*/ [XTABLE3].ID IS NULL
AND /*27b*/ [XTABLE5].ID IS NULL
... and tens of similar lines
AND /*27b*/ [XTABLE131].ID IS NULL);
You are OUTER JOIN'ing the queries, so, when you start putting stuff in the WHERE clause from the result of the OUTER JOIN table expressions (derived table in this case) then it will more than likely be treat as an INNER JOIN - you can see that by checking the query plan.

Hash Match Aggregate Cost

I'm trying to optimize a particular query
I tried with hash tables but the performance didn't improved so much
I need to join the same table three times - pratichesteps - and then finally join with - pratiche - table
This is the query
SELECT DISTINCT dbo.PRATICHESTEPS.IDPraticaStep AS IDPraticaEsame,
PRATICHESTEPS_3.IDPraticaStep AS IDPraticaCatena,
dbo.PRATICHE.IDSysStato AS IDStatoCatena,
dbo.PRATICHE.IDPraticaAccorpata,
PRATICHESTEPS_3.IDAnalisiStep,
dbo.PRATICHE.IDTipoAtto,
PRATICHESTEPS_3.Accorpamento,
dbo.PRATICHE.DataRegistrazione,
PRATICHESTEPS_3.LastStep
FROM dbo.PRATICHESTEPS
INNER JOIN dbo.PRATICHESTEPS AS PRATICHESTEPS_1
ON dbo.PRATICHESTEPS.IDPraticaCarico = PRATICHESTEPS_1.IDPraticaCarico
INNER JOIN dbo.PRATICHESTEPS AS PRATICHESTEPS_2
ON PRATICHESTEPS_1.IDPraticaStep = PRATICHESTEPS_2.IDPraticaStep
INNER JOIN dbo.PRATICHESTEPS AS PRATICHESTEPS_3
ON PRATICHESTEPS_2.IDPraticaCarico = PRATICHESTEPS_3.IDPraticaCarico
INNER JOIN dbo.PRATICHE
ON PRATICHESTEPS_3.IDPraticaStep = dbo.PRATICHE.IDPratica

SQL Query to retrieve single record per filter

I have the following query:
SELECT min(salesorder.SOM_SalesOrderID) AS salesorder,
Item.IMA_ItemID,
Item.IMA_ItemName,
Customer.CUS_CorpName,
WK.WKO_WorkOrderID,
min(WK.WKO_OrigRequiredDate),
WK.WKO_WorkOrderTypeCode,
min(WK.WKO_RequiredDate),
max(WK.WKO_LastWorkDate),
min(wk.WKO_RequiredQty),
wk.WKO_MatlIssueDate,
min(SalesOrderDelivery.SOD_RequiredQty),
Item.IMA_ItemTypeCode,
Item.IMA_OnHandQty,
min(SalesOrderDelivery.SOD_PromiseDate),
min(WO.woo_operationseqID) AS seqid
FROM SalesOrder
INNER JOIN SalesOrderLine ON SalesOrder.SOM_RecordID = SalesOrderLine.SOI_SOM_RecordID
INNER JOIN SalesOrderDelivery ON SalesOrderLine.SOI_RecordID = SalesOrderDelivery.SOD_SOI_RecordID,
WO.
INNER JOIN Item ON SalesOrderLine.SOI_IMA_RecordID = Item.IMA_RecordID
INNER JOIN WKO wk ON Item.IMA_ItemID = WK.WKO_ItemID
INNER JOIN Customer ON SalesOrder.SOM_CUS_RecordID = Customer.CUS_RecordID
INNER JOIN woo WO ON WO.WOO_WorkOrderID = WK.WKO_WorkOrderID
WHERE wk.WKO_StatusCode = 'Released'
AND WO.WOO_StatusCode IS NULL
AND SalesOrderDelivery.SOD_ShipComplete = 'false'
GROUP BY WK.WKO_WorkOrderID,
Item.IMA_ItemID,
Item.IMA_ItemName,
Customer.CUS_CorpName,
WK.WKO_WorkOrderTypeCode,
wk.WKO_MatlIssueDate,
Item.IMA_ItemTypeCode,
Item.IMA_OnHandQty
I need 1 record returned for each wk.wko_workorderid. There is a field that is not included that I'm not sure how to get. I need to retrieve the woo.woo_workcenterid that corresponds to min(WO.woo_operationseqID)as seqid. I cannot include it in the general query since there are multiple workcenterids in the table and I only want the specific one that is part of the min operation sequence record.
Any help would be appreciated.