JOIN Optimization with CASE expressions in WHERE - sql

The 2 tables below will pull a world of data from details_2 table but will join to the fields based on different reason coded in #exceptions table.
Is there a better way to write the below query?
Select
a.Fieldname1,
a.Fieldname2,
a.fieldname3
from
#Exceptions a, [DETAILS_2] b
where
(case when a.REASON_CD = 'LOBMKT' then CONCAT(a.LOB_CD,a.GEO_MARKET) end = concat(b.LOB_CD,b.GEO_MARKET)) or
(case when a.REASON_CD = 'LOB' then a.LOB_CD end = b.LOB_CD) or
(case when a.REASON_CD = 'CAT' then a.CTRCT_CAT_CD end = b.CTRCT_CAT_CD) or
(case when a.REASON_CD = 'LOBST' then CONCAT(a.LOB_CD,a.[derived_GEO_MARKET]) end = concat(b.LOB_CD,b.GEO_MARKET))

I think I would go for this, howver not able to test anything without sample data and desired output like Cetin also mentiones.
I would go for the UNION ALL, as the data should be unique in all different statements. So SQL does not need to verify that (with costing more CPU)
SELECT
a.Fieldname1,
a.Fieldname2,
a.fieldname3
FROM #Exceptions a
JOIN [DETAILS_2] b ON a.REASON_CD = 'LOBMKT'
AND a.LOB_CD = b.LOB_CD
AND a.GEO_MARKET = b.GEO_MARKET
UNION ALL
SELECT
a.Fieldname1,
a.Fieldname2,
a.fieldname3
FROM #Exceptions a
JOIN [DETAILS_2] b ON a.REASON_CD = 'LOB'
AND a.LOB_CD = b.LOB_CD
UNION ALL
SELECT
a.Fieldname1,
a.Fieldname2,
a.fieldname3
FROM #Exceptions a
JOIN [DETAILS_2] b ON a.REASON_CD = 'CAT'
AND a.CTRCT_CAT_CD = b.CTRCT_CAT_CD
UNION ALL
SELECT
a.Fieldname1,
a.Fieldname2,
a.fieldname3
FROM #Exceptions a
JOIN [DETAILS_2] b ON a.REASON_CD = 'LOBST'
AND a.LOB_CD = b.LOB_CD
AND a.[derived_GEO_MARKET] = b.GEO_MARKET;

This approach is sargable and easier to understand what it is doing:
Select a.Fieldname1, a.Fieldname2, a.fieldname3
from #Exceptions a
inner join [DETAILS_2] b on a.LOB_CD = b.LOB_CD and a.GEO_MARKET = b.GEO_MARKET
where a.REASON_CD = 'LOBMKT'
UNION ALL
Select a.Fieldname1, a.Fieldname2, a.fieldname3
from #Exceptions a
inner join [DETAILS_2] b on a.LOB_CD = b.LOB_CD
where a.REASON_CD = 'LOB'
UNION ALL
Select a.Fieldname1, a.Fieldname2, a.fieldname3
from #Exceptions a
inner join [DETAILS_2] b on a.CTRCT_CAT_CD = b.CTRCT_CAT_CD
where a.REASON_CD = 'CAT'
UNION ALL
Select a.Fieldname1, a.Fieldname2, a.fieldname3
from #Exceptions a
inner join [DETAILS_2] b on a.LOB_CD = b.LOB_CD and a.[derived_GEO_MARKET] = b.GEO_MARKET
where a.REASON_CD = 'LOBST'

(Beware you are doing a cross join)
SELECT a.Fieldname1,
a.Fieldname2,
a.fieldname3
FROM #Exceptions a,
[DETAILS_2] b
WHERE (
a.REASON_CD = 'LOBMKT'
AND a.LOB_CD = b.LOB_CD
AND a.GEO_MARKET = b.GEO_MARKET
)
OR
(
a.REASON_CD = 'LOB'
AND a.LOB_CD = b.LOB_CD
)
OR
(
a.REASON_CD = 'CAT'
AND a.CTRCT_CAT_CD = b.CTRCT_CAT_CD
)
OR
(
a.REASON_CD = 'LOBST'
AND a.LOB_CD = b.LOB_CD
AND a.[derived_GEO_MARKET] = b.GEO_MARKET
);

Related

Updating a Java sql query from UNION to JOIN

I have the following query,
table PCA and PC have similar structure (same columns).
select session, wc, sum(duration) / (sum(delta) + sum(duration)) as wc_efficiency from
(
SELECT
a.session, a.panel,
a.line_location as WC,
a.line_duration as duration,
a.line_lead_duration - b.line_lead_duration as delta
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.line_location is not null
union
SELECT
a.session, a.panel,
a.completion_location as WC2,
a.completion_duration as duration2,
a.completion_lead_duration - b.completion_lead_duration as delta2
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.completion_location is not null
)
group by session, wc
Now, I want to find wc2 & wc_efficiency2 disjointedly for duration2 & delta2 as separate columns. To achieve that I update my queries as follows:
select session, wc1, sum(duration1) / (sum(delta1) + sum(duration1)) as wc_efficiency1, wc2, sum(duration2) / (sum(delta2) + sum(duration2)) as wc_efficiency2 from
(
SELECT
a.session as ss, a.panel as pl,
a.line_location as WC1,
a.line_duration as duration1,
a.line_lead_duration - b.line_lead_duration as delta1
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.line_location is not null
) t1
join
(
SELECT
a.session as ss, a.panel as pl,
a.completion_location as WC2,
a.completion_duration as duration2,
a.completion_lead_duration - b.completion_lead_duration as delta2
FROM PCA a
join PC b
on a.batch = b.batch and a.session = b.session and a.panel = b.panel
where a.completion_location is not null
) t2
ON t1.ss = t2.ss and t1.pl = t2.pl
group by wc1, wc2
The query does not run, I can't find the error.

Max Query Over Partition

I want to select max values related to query, but all results are coming. Any idea ?
QUERY
SELECT MAXRecID,MAXSetID,MAXRID,PreReifiedValue,ComplianceState
FROM v_CI_CurrentComplianceStatus as A
INNER JOIN v_CIRules as B
ON B.CI_ID = A.CI_ID
INNER JOIN v_R_System as C
ON C.ResourceID = A.ItemKey
INNER JOIN
( SELECT PreReifiedValue,setting_CI_ID,
MAX(RecordID) AS MAXRecID,
MAX(SettingID) AS MAXSetID,
MAX(RuleID) AS MAXRID
FROM CI_CurrentRuleDetail
GROUP BY PreReifiedValue,Setting_CI_ID,instancedata
) AS D
ON D.Setting_CI_ID = A.CI_ID
GROUP by MAXRecID,MAXSetID,MAXRID,PreReifiedValue,rulename,ComplianceState
Results
MAXRecID MAXSetID MAXRID PreReifiedValue ComplianceState
72057594038117564 16780566 16780622 10 2
72057594038117565 16780570 16780620 0 2
Try this query
SELECT
MAX(tmp.MAXRecID), MAX(tmp.MAXSetID), MAX(tmp.MAXRID), MAX(tmp.PreReifiedValue), MAX(tmp.ComplianceState)
FROM (
SELECT MAXRecID,MAXSetID,MAXRID,PreReifiedValue,ComplianceState
FROM v_CI_CurrentComplianceStatus as A
INNER JOIN v_CIRules as B
ON B.CI_ID = A.CI_ID
INNER JOIN v_R_System as C
ON C.ResourceID = A.ItemKey
INNER JOIN
( SELECT PreReifiedValue,setting_CI_ID,
MAX(RecordID) AS MAXRecID,
MAX(SettingID) AS MAXSetID,
MAX(RuleID) AS MAXRID
FROM CI_CurrentRuleDetail
GROUP BY PreReifiedValue,Setting_CI_ID,instancedata
) AS D
ON D.Setting_CI_ID = A.CI_ID
) AS tmp
GROUP by tmp.MAXRecID, tmp.MAXSetID, tmp.MAXRID, tmp.PreReifiedValue, tmp.rulename, tmp.ComplianceState

SQL Stored Procedure Combine UNION rows into 1 row

I would love to know how to put the results of this query into one row instead of 3 rows it gives back:
SELECT COUNT([fms].[dbo].[Booking].BOOKINGNUMBER) FROM [fms].[dbo].[Booking]
INNER JOIN [fms].[dbo].[Container] ON [fms].[dbo].[Booking].[BOOKINGNUMBER] = [fms].[dbo].[Container].[BOOKINGNUMBER]
INNER JOIN [fms].[dbo].[File] ON [fms].[dbo].[Container].FILENUMBER = [fms].[dbo].[File].FILENUMBER
WHERE [fms].[dbo].[Booking].RELATIONCODE = 'SHIP02' AND [fms].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28'
UNION ALL
SELECT COUNT([fmsAir].[dbo].[Booking].BOOKINGNUMBER) FROM [fmsAir].[dbo].[Booking]
INNER JOIN [fmsAir].[dbo].[Container] ON [fmsAir].[dbo].[Booking].[BOOKINGNUMBER] = [fmsAir].[dbo].[Container].[BOOKINGNUMBER]
INNER JOIN [fmsAir].[dbo].[File] ON [fmsAir].[dbo].[Container].FILENUMBER = [fmsAir].[dbo].[File].FILENUMBER
WHERE [fmsAir].[dbo].[Booking].RELATIONCODE = 'SHIP02' AND [fmsAir].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28'
UNION ALL
SELECT COUNT([fmsProjects].[dbo].[Booking].BOOKINGNUMBER) FROM [fmsProjects].[dbo].[Booking]
INNER JOIN [fmsProjects].[dbo].[Container] ON [fmsProjects].[dbo].[Booking].[BOOKINGNUMBER] = [fmsProjects].[dbo].[Container].[BOOKINGNUMBER]
INNER JOIN [fmsProjects].[dbo].[File] ON [fmsProjects].[dbo].[Container].FILENUMBER = [fmsProjects].[dbo].[File].FILENUMBER
WHERE [fmsProjects].[dbo].[Booking].RELATIONCODE = 'SHIP02' AND [fmsProjects].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28'
Is there a way that I can combine the 3 result rows and count them into 1 row. I am using this inside a stored procedure.
If you want to SUM all the count of all 3 SELECT queries, You could you this:
SELECT SUM(cnt)
FROM(
SELECT COUNT([fms].[dbo].[Booking].BOOKINGNUMBER) cnt
FROM [fms].[dbo].[Booking]
INNER JOIN [fms].[dbo].[Container] ON [fms].[dbo].[Booking].[BOOKINGNUMBER] = [fms].[dbo].[Container].[BOOKINGNUMBER]
INNER JOIN [fms].[dbo].[File] ON [fms].[dbo].[Container].FILENUMBER = [fms].[dbo].[File].FILENUMBER
WHERE [fms].[dbo].[Booking].RELATIONCODE = 'SHIP02' AND [fms].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28'
UNION ALL
SELECT COUNT([fmsAir].[dbo].[Booking].BOOKINGNUMBER)
FROM [fmsAir].[dbo].[Booking]
INNER JOIN [fmsAir].[dbo].[Container] ON [fmsAir].[dbo].[Booking].[BOOKINGNUMBER] = [fmsAir].[dbo].[Container].[BOOKINGNUMBER]
INNER JOIN [fmsAir].[dbo].[File] ON [fmsAir].[dbo].[Container].FILENUMBER = [fmsAir].[dbo].[File].FILENUMBER
WHERE [fmsAir].[dbo].[Booking].RELATIONCODE = 'SHIP02' AND [fmsAir].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28'
UNION ALL
SELECT COUNT([fmsProjects].[dbo].[Booking].BOOKINGNUMBER)
FROM [fmsProjects].[dbo].[Booking]
INNER JOIN [fmsProjects].[dbo].[Container] ON [fmsProjects].[dbo].[Booking].[BOOKINGNUMBER] = [fmsProjects].[dbo].[Container].[BOOKINGNUMBER]
INNER JOIN [fmsProjects].[dbo].[File] ON [fmsProjects].[dbo].[Container].FILENUMBER = [fmsProjects].[dbo].[File].FILENUMBER
WHERE [fmsProjects].[dbo].[Booking].RELATIONCODE = 'SHIP02' AND [fmsProjects].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28'
) AS tmp;
Here is one way
SELECT (SELECT Count([fms].[dbo].[Booking].BOOKINGNUMBER)
FROM [fms].[dbo].[Booking]
.......
WHERE [fms].[dbo].[Booking].RELATIONCODE = 'SHIP02'
AND [fms].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28') as fms_count,
(SELECT Count([fmsAir].[dbo].[Booking].BOOKINGNUMBER)
FROM [fmsAir].[dbo].[Booking]
.......
WHERE [fmsAir].[dbo].[Booking].RELATIONCODE = 'SHIP02'
AND [fmsAir].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28') as fmsAir_count,
(SELECT Count([fmsProjects].[dbo].[Booking].BOOKINGNUMBER)
FROM [fmsProjects].[dbo].[Booking]
.....
WHERE [fmsProjects].[dbo].[Booking].RELATIONCODE = 'SHIP02'
AND [fmsProjects].[dbo].[File].ETA BETWEEN '2000-10-27' AND '2016-10-28') as fmsProjects_count
Who can read such a query? Use table aliases!
SELECT COUNT(b.BOOKINGNUMBER)
FROM [fms].[dbo].[Booking] b INNER JOIN
[fms].[dbo].[Container] c
ON b.[BOOKINGNUMBER] = c.[BOOKINGNUMBER] INNER JOIN
[fms].[dbo].[File] f
ON [c.FILENUMBER = f.FILENUMBER
WHERE b.RELATIONCODE = 'SHIP02' AND [f.ETA BETWEEN '2000-10-27' AND '2016-10-28';
As for getting these in one row, one method is just to use subqueries:
SELECT (SELECT COUNT(b.BOOKINGNUMBER)
FROM [fms].[dbo].[Booking] b INNER JOIN
[fms].[dbo].[Container] c
ON b.[BOOKINGNUMBER] = c.[BOOKINGNUMBER] INNER JOIN
[fms].[dbo].[File] f
ON [c.FILENUMBER = f.FILENUMBER
WHERE b.RELATIONCODE = 'SHIP02' AND [f.ETA BETWEEN '2000-10-27' AND '2016-10-28'
) as fms_count,
(SELECT COUNT(b.BOOKINGNUMBER)
FROM [fmsair].[dbo].[Booking] b INNER JOIN
[fmsair].[dbo].[Container] c
ON b.[BOOKINGNUMBER] = c.[BOOKINGNUMBER] INNER JOIN
[fmsair].[dbo].[File] f
ON [c.FILENUMBER = f.FILENUMBER
WHERE b.RELATIONCODE = 'SHIP02' AND [f.ETA BETWEEN '2000-10-27' AND '2016-10-28'
) as fmsair_count,
(SELECT COUNT(b.BOOKINGNUMBER)
FROM [fmsprojects].[dbo].[Booking] b INNER JOIN
[fmsprojects].[dbo].[Container] c
ON b.[BOOKINGNUMBER] = c.[BOOKINGNUMBER] INNER JOIN
[fmsprojects].[dbo].[File] f
ON [c.FILENUMBER = f.FILENUMBER
WHERE b.RELATIONCODE = 'SHIP02' AND [f.ETA BETWEEN '2000-10-27' AND '2016-10-28'
) as fmsprojects_count

Not able to adress field in nested query

I have such a query:
select d.r_object_id,
(select max(max_date) from (
SELECT max(sys_s.r_modify_date) AS max_date
FROM kc_mission_s mis_s, dm_sysobject_s sys_s
WHERE mis_s.r_object_id = sys_s.r_object_id AND mis_s.ka_document = d.r_object_id
union all
SELECT sys_s.r_modify_date AS max_date
FROM dm_document_s doc_s left join dm_sysobject_s sys_s on doc_s.r_object_id = sys_s.r_object_id
WHERE doc_s.r_object_id = d.r_object_id
)) as maxx
from kc_document_s d
The field d.r_object_id is not visible from the last nested query.
It will be visible if in-between query will be removed like this:
select d.r_object_id,
(
SELECT max(sys_s.r_modify_date) AS max_date
FROM kc_mission_s mis_s, dm_sysobject_s sys_s
WHERE mis_s.r_object_id = sys_s.r_object_id AND mis_s.ka_document = d.r_object_id
union all
SELECT sys_s.r_modify_date AS max_date
FROM dm_document_s doc_s left join dm_sysobject_s sys_s on doc_s.r_object_id = sys_s.r_object_id
WHERE doc_s.r_object_id = d.r_object_id
) as maxx
from kc_document_s d
But in this case I'm not allowed to select multiple rows.
What should I do?
If you continue the join from the middle level query into the lowest level query, and also include the join column at each level, then it should work
select d.r_object_id,
(select max(max_date) from (
SELECT max(sys_s.r_modify_date) AS max_date,
d.r_object_id
FROM kc_mission_s mis_s, dm_sysobject_s sys_s
WHERE mis_s.r_object_id = sys_s.r_object_id AND mis_s.ka_document = d.r_object_id
union all
SELECT sys_s.r_modify_date AS max_date,
d.r_object_id
FROM dm_document_s doc_s left join dm_sysobject_s sys_s on doc_s.r_object_id = sys_s.r_object_id
WHERE doc_s.r_object_id = d.r_object_id
) sub_query
where sub_query.r_object_id = d.r_object_id
) as maxx
from kc_document_s d
try this
select d.r_object_id,
greatest((select max(sys_s.r_modify_date) as max_date
from kc_mission_s mis_s, dm_sysobject_s sys_s
where mis_s.r_object_id = sys_s.r_object_id
and mis_s.ka_document = d.r_object_id),
(select sys_s.r_modify_date as max_date
from dm_document_s doc_s
left join dm_sysobject_s sys_s
on doc_s.r_object_id = sys_s.r_object_id
where doc_s.r_object_id = d.r_object_id)
) as maxx
from kc_document_s d

Could use advice in making my query smarter

Hi Guys I have the following query but the unions make it quite heavy so could anyone help in fixing my query.
There are 3 scenarios.
1. pack_no = pack of an item (inside packitem)
2. item = item inside pack (inside packitem)
3. item = doesn't have pack (inside item_master)
SELECT DISTINCT item, loc FROM
(SELECT e.pack_no item, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
LEFT JOIN packitem e
ON (b.item = e.pack_no or c.item = e.pack_no) AND d.item = e.pack_no
WHERE d.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' AND f.sh_trade_unit = 'Y')
UNION
SELECT e.item, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
LEFT JOIN packitem e
ON (b.item = e.pack_no or c.item = e.pack_no)
WHERE e.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' AND f.sh_trade_unit = 'Y')
UNION
SELECT d.item, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
WHERE d.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' and f.sh_trade_unit = 'Y')
);
The simplest way to improve the performance of the query would be to change the UNIONs to UNION ALLs - that way, the query only has to eliminate duplicates once.
However, it should be possible to simplify this query to:
WITH CTE AS
(SELECT d.item d_item, e.item e_item, e.pack_no e_pack_no, g.store loc
FROM dc_store_ranging a
JOIN store g
ON g.store_name_secondary = CAST(a.loc AS VARCHAR2(150 BYTE)) AND
g.store_close_date >= SYSDATE
LEFT JOIN dc_pim_export_vert b
ON a.dpac = b.dpac AND b.artikel_type_LMS NOT IN ('S','V')
LEFT JOIN dc_ccn190_sid_vtb c ON a.dpac = c.dpac
JOIN item_master d
ON (b.item = d.item OR c.item = d.item) AND d.status = 'A'
LEFT JOIN packitem e
ON (b.item = e.pack_no or c.item = e.pack_no)
)
SELECT DISTINCT item, loc FROM
(--SELECT e_pack_no item, loc FROM CTE WHERE d_item = e_pack_no UNION ALL -- this select is a subset of the third select
SELECT e_item item, loc FROM CTE UNION ALL
SELECT d_item item, loc FROM CTE) uc
WHERE uc.item NOT IN
(SELECT f.item
FROM item_attributes f
WHERE f.sh_store_order_unit = 'N' and f.sh_trade_unit = 'Y')