Improve performance on SELECT CASE with Partition Plus COUNT - sql

I have revised the code based on suggestions but now performance has dwindled. Any suggestions are welcome
select *
from (
SELECT
d.ID,
d.HeaderId,
CASE WHEN h.MyType = 'C' THEN
RANK() OVER (PARTITION BY l.Work ORDER BY l.Address1 DESC)
ELSE
RANK() OVER (PARTITION BY l.Home ORDER BY l.Address1 DESC)
END
AS 'RANK',
CASE WHEN h.MyType = 'C' THEN
COUNT(l.Work) OVER (PARTITION BY l.Work)
ELSE
COUNT(l.Home) OVER (PARTITION BY l.Home)
END
AS 'MAXCOUNT'
FROM schema1.Details AS d
JOIN schema1.BatchHeader AS h
ON d.HeaderId = h.ID
JOIN schema2.Details AS l
ON d.LeadBatchDetailId = l.Id
LEFT JOIN LDCs AS ldcElec
ON l.LDC_Elec = schema3.Code
LEFT JOIN LDCs AS ldcGas
ON l.ldc_gas = ldcGas.Code
LEFT JOIN schema2.Accounts ag
ON (l.Work = ag.Phone AND 'G' = ag.Business AND h.MyType = 'C')
OR (l.Home = ag.Phone AND 'G' = ag.Business AND h.MyType = 'R')
LEFT JOIN schema2.Accounts ae
ON (l.Work = ae.Phone AND 'E' = ae.Business AND h.MyType = 'C')
OR (l.Home = ae.Phone AND 'E' = ae.Business AND h.MyType = 'R')
WHERE d.HeaderId = #Id)
) a
WHERE [RANK] = [MAXCOUNT]
ORDER BY LdcGasName, LdcElecName

I don’t believe SQL does that, supporting AND-type logic embedded within the ranking function that way. You might need to break it into further subqueries. Some extreme psuedo-code:
Select rank over work for ‘C’
Full outer join select rank over home for “R”
Make that a subquery, with the outer query performing the coalesce and all the outer joins
But then you have to deal with the COUNT... OVER..., and that count is not dependant upon h.MyType = C or R, which makes me wonder if that MAXCOUNT will end up equallying the ranking values which are so constrained.
This all assumes I'm reading it right... but it's a complex query, and hard to understand without knowledge of the underlying tables and business logic.

Related

Aggregate rows inside new columns

I would like to join the two first tables (Product and ProductProperties) to get the result in the bottom.
How do I do this?
There are penalties for EAV. I'm not saying EAV is evil, but should be deployed carefully and with great forethought.
Here are two examples. The first is a PIVOT, and the second is a conditional aggregation.
I tend to lean towards the conditional aggregation, it offers more flexibility and often a performance bump
Untested for you did not supply sample data and desired results as text
Select *
From (
Select A.product_id
,A.product_name
,B.product_property
,B.product_property_value
From Product A
Join ProductProperties B on A.product_id=B.product_di
) src
Pivot (max( product_property_value ) for product_property in ([Price],[Category],[Status] ) ) pvt
Select A.product_id
,A.product_name
,Price = max( case when product_propery='Price' then product_propery_value end)
,Category = max( case when product_propery='Category' then product_propery_value end)
,Status = max( case when product_propery='Status' then product_propery_value end)
From Product A
Join ProductProperties B on A.product_id=B.product_di
Group By A.product_id,A.product_name
SELECT
b.product_id
,b.product_name
,Price = MAX(IIF(p.product_property = 'Price',p.product_property_value,NULL))
,Category = MAX(IIF(p.product_property = 'Category',p.product_property_value,NULL))
,Status = MAX(IIF(p.product_property = 'Status',p.product_property_value,NULL))
FROM books b (nolock)
JOIN prodprop p (nolock)
ON b.product_id = p.product_id
GROUP BY b.product_id,b.product_name

Update with ROW_NUMBER() OVER

I'm getting error "Windowed functions can only appear in the SELECT or ORDER BY clauses." Can you please help me?
Iknow there are already some solutions to this problem but i don't know how to change it for my case. I am a beginner in SQL.
EDIT: I need to update column [BREAG_GUEST_SEQ] with correct sequence at UPDATE case. Every [BREAG_BGL_ID] have own sequence..
UPDATE G1
SET
G1.[BREAG_BGL_ID] = CASE WHEN G1.[BREAG_BGL_ID] <> G2.GROUP_ID THEN G2.GROUP_ID ELSE G1.[BREAG_BGL_ID] END
,G1.[BREAG_GUEST_SEQ] = CASE WHEN G1.[BREAG_BGL_ID] <> G2.GROUP_ID THEN ROW_NUMBER() OVER(ORDER BY G1.[BREAG_BRE_ID] DESC) + (SELECT ISNULL(MAX(BREAG_GUEST_SEQ), 0) FROM BOS_RESADDGUEST
WHERE DATEPART(YEAR, BREAG_DATEFROM) = DATEPART(YEAR, GETDATE()) AND BREAG_BGL_ID = G2.GROUP_ID)
ELSE G1.[BREAG_GUEST_SEQ] END
FROM
BOS_RESADDGUEST G1
INNER JOIN (
SELECT
[BRE_ID]
,MAX([BRE_DATEFROM]) AS DATEFROM
,MAX([BRE_DATETO]) AS DATETO
,MAX(BGL_ID) AS GROUP_ID
FROM
BOS_RESERVATION
LEFT JOIN BOS_UNIT_LIST ON BUL_ID = BRE_UNIT_ID
LEFT JOIN BOS_UNITTYPE_LIST ON BUL_UNITTYPE_ID = BUT_ID
LEFT JOIN BOS_GROUP_LIST ON BGL_ID = BUT_GROUP_ID
WHERE
BRE_ID = #DIALOG_BRE_ID
GROUP BY [BRE_ID]
) AS G2
ON G2.[BRE_ID] = G1.[BREAG_BRE_ID]
This isnt tested nor do you provide expected results or data structure. However, the issue is quite clear (as SMor has pointed out in the comments). This isnt the best code and the indentation is awful (i want it to be readable with scrolling left or right here on SO).
You most likely have to edit what Im joining on in the update statement at the end, because without further information from you i have to guess what the join predicate ought to be. Im sure you can figure it out from this point forward.
; WITH cte AS
(
SELECT
[BREAG_BRE_ID]
, CASE
WHEN x.[BREAG_BGL_ID] <> x.GROUP_ID THEN x.GROUP_ID
ELSE x.[BREAG_BGL_ID]
END As NewBREAGBGLID
, CASE
WHEN x.[BREAG_BGL_ID] <> x.GROUP_ID THEN ROW_NUMBER()
OVER (ORDER BY x.[BREAG_BRE_ID] DESC) +
(
SELECT ISNULL(MAX(BREAG_GUEST_SEQ), 0)
FROM BOS_RESADDGUEST
WHERE DATEPART(YEAR, BREAG_DATEFROM) = DATEPART(YEAR, GETDATE())
AND BREAG_BGL_ID = x.GROUP_ID
)
ELSE x.[BREAG_GUEST_SEQ]
END AS NewBREAGGUESTSEQ
FROM
(
SELECT g2.*, g1.[BREAG_BGL_ID], g1.[BREAG_BRE_ID], g1.[BREAG_GUEST_SEQ]
FROM
BOS_RESADDGUEST G1
INNER JOIN
(
SELECT
[BRE_ID]
,MAX([BRE_DATEFROM]) AS DATEFROM
,MAX([BRE_DATETO]) AS DATETO
,MAX(BGL_ID) AS GROUP_ID
FROM
BOS_RESERVATION
LEFT JOIN BOS_UNIT_LIST ON BUL_ID = BRE_UNIT_ID
LEFT JOIN BOS_UNITTYPE_LIST ON BUL_UNITTYPE_ID = BUT_ID
LEFT JOIN BOS_GROUP_LIST ON BGL_ID = BUT_GROUP_ID
WHERE
BRE_ID = #DIALOG_BRE_ID
GROUP BY [BRE_ID]
) AS G2
ON G2.[BRE_ID] = G1.[BREAG_BRE_ID]
) AS x
)
UPDATE
[BREAG_BGL_ID] = c.NewBREAGBGLID
, [BREAG_GUEST_SEQ] = c.NewBREAGGUESTSEQ
FROM BOS_RESADDGUEST br
INNER JOIN cte c ON br.[BREAG_BRE_ID] =c.[BREAG_BRE_ID]
You need to move the ROW_NUMBER into a derived table or CTE. You can update this directly, no need to rejoin.
You can also change the subquery to a windowed MAX
Note also that date comparisons should not use functions against the column, as this can affect performance
UPDATE G1
SET
G1.[BREAG_BGL_ID] = CASE WHEN G1.[BREAG_BGL_ID] <> G2.GROUP_ID THEN G2.GROUP_ID ELSE G1.[BREAG_BGL_ID] END
,G1.[BREAG_GUEST_SEQ] = CASE WHEN G1.[BREAG_BGL_ID] <> G2.GROUP_ID THEN G1.rn + G1.MaxSeq ELSE G1.[BREAG_GUEST_SEQ] END
FROM (
SELECT *,
ROW_NUMBER() OVER(ORDER BY G1.[BREAG_BRE_ID] DESC) AS rn,
ISNULL(MAX(CASE WHEN WHERE G1.BREAG_DATEFROM >= DATEFROMPARTS(YEAR(GETDATE()), 1, 1) THEN G1.BREAG_GUEST_SEQ END)
OVER (PARTITION BY G1.BREAG_BGL_ID), 0) AS MaxSeq
FROM
BOS_RESADDGUEST G1
) AS G1
INNER JOIN (
SELECT
[BRE_ID]
,MAX([BRE_DATEFROM]) AS DATEFROM
,MAX([BRE_DATETO]) AS DATETO
,MAX(BGL_ID) AS GROUP_ID
FROM
BOS_RESERVATION
LEFT JOIN BOS_UNIT_LIST ON BUL_ID = BRE_UNIT_ID
LEFT JOIN BOS_UNITTYPE_LIST ON BUL_UNITTYPE_ID = BUT_ID
LEFT JOIN BOS_GROUP_LIST ON BGL_ID = BUT_GROUP_ID
WHERE
BRE_ID = #DIALOG_BRE_ID
GROUP BY [BRE_ID]
) AS G2
ON G2.[BRE_ID] = G1.[BREAG_BRE_ID];

Combine two queries to get the data in two columns

SELECT
tblEmployeeMaster.TeamName, SUM(tblData.Quantity) AS 'TotalQuantity'
FROM
tblData
INNER JOIN
tblEmployeeMaster ON tblData.EntryByHQCode = tblEmployeeMaster.E_HQCode
INNER JOIN
tblPhotos ON tblEmployeeMaster.TeamNo = tblPhotos.TeamNo
WHERE
IsPSR = 'Y'
GROUP BY
tblPhotos.TeamSort, tblPhotos.TeamNo, tblPhotos.Data,
tblEmployeeMaster.TeamName
ORDER BY
tblPhotos.TeamSort DESC, TotalQuantity DESC
This returns
Using this statement
select TeamName, count(TeamName) AS 'Head Count'
from dbo.tblEmployeeMaster
where IsPSR = 'Y'
group by teamname
Which returns
I would like to combine these 2 queries in 1 to get the below result.
Tried union / union all but no success :(
Any help will be very much helpful.
You can simply use the sub-query as follows:
SELECT tblEmployeeMaster.TeamName, SUM(tblData.Quantity) AS 'TotalQuantity',
MAX(HEAD_COUNT) AS HEAD_COUNT, -- USE THIS VALUE FROM SUB-QUERY
CASE WHEN MAX(HEAD_COUNT) <> 0
THEN SUM(tblData.Quantity)/MAX(HEAD_COUNT)
END AS PER_MAN_CONTRIBUTION -- column asked in comment
FROM tblData INNER JOIN
tblEmployeeMaster ON tblData.EntryByHQCode = tblEmployeeMaster.E_HQCode INNER JOIN
tblPhotos ON tblEmployeeMaster.TeamNo = tblPhotos.TeamNo
-- FOLLOWING SUB-QUERY CAN BE USED
LEFT JOIN (select TeamName, count(TeamName) AS HEAD_COUNT
from dbo.tblEmployeeMaster
where IsPSR = 'Y' group by teamname) AS HC
ON HC.TeamName = tblEmployeeMaster.TeamName
where IsPSR = 'Y'
GROUP BY tblPhotos.TeamSort, tblPhotos.TeamNo, tblPhotos.Data,tblEmployeeMaster.TeamName
order by tblPhotos.TeamSort desc, TotalQuantity desc

Oracle SQL Correlated subquery - Returning count(*) in some columns

I have my initial statement which is :
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
I want to calculate some "flags" and return them in my initial statement.
There are 3 flags which can be calculated like this :
1) Flag ISMASTER:
SELECT Count(*)
FROM TEAM_TEAM_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.RLTD_TEAM_ID
AND CODE = 'Double';
2) Flag ISAGENT:
SELECT Count(*)
FROM TEAM_ROL_REL A, TEAM B
WHERE B.PARTY_PTY_ID = A.TEAM_ID;
3) Flag NUMPACTS:
SELECT Count(*)
FROM TEAM_ROL_REL A,
TEAM_ROL_POL_REL B,
PERSO_POL_STA_REL C,
TEAM D
WHERE A.ROL_CD IN ('1','2')
AND A.T_ROL_REL_ID = B.P_ROL_REL_ID
AND B.P_POL_ID = C.P_POL_ID
AND C.STA_CD = 'A'
AND D.PARTY_PTY_ID = A.TEAM_ID;
To try to achieve this, I've updated my initial statement like this :
WITH ABC AS (
SELECT TEAM.ID PKEY_SRC_OBJECT,
TEAM.MODF_DAT UPDATE_DATE,
TEAM.MODF_USR UPDATED_BY,
PERSO.FIRST_NAM FISRT_NAME
FROM TEAM
LEFT OUTER JOIN PERSO ON (TEAM.ID=PERSO.TEAM_ID)
)
SELECT ABC.*, MAST.ISMASTER, AGENT.ISAGENT, PACTS.NUMPACTS FROM ABC
LEFT OUTER JOIN (
select
RLTD_TEAM_ID,
Count(RLTD_TEAM_ID) OVER (PARTITION BY RLTD_TEAM_ID) as ISMASTER
FROM TEAM_TEAM_REL
WHERE CODE = 'Double'
) MAST
ON ABC.PKEY_SRC_OBJECT = MAST.RLTD_TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as ISAGENT
FROM TEAM_ROL_REL
) AGENT
ON ABC.PKEY_SRC_OBJECT = AGENT.TEAM_ID
LEFT OUTER JOIN (
select
TEAM_ID,
Count(TEAM_ID) OVER (PARTITION BY TEAM_ID) as NUMPACTS
FROM TEAM_ROL_REL, TEAM_ROL_POL_REL, PERSO_POL_STA_REL
WHERE TEAM_ROL_REL.ROL_CD IN ('1','2')
AND TEAM_ROL_REL.T_ROL_REL_ID = TEAM_ROL_POL_REL.P_ROL_REL_ID
AND TEAM_ROL_POL_REL.P_POL_ID = PERSO_POL_STA_REL.P_POL_ID
AND PERSO_POL_STA_REL.STA_CD = 'A'
) PACTS
ON ABC.PKEY_SRC_OBJECT = PACTS.TEAM_ID;
For the two first flags (ISMASTER and ISAGENT) I get the result in less than 1min, but for the last flag (NUMPACTS) it runs few minutes without provide any result.
I think my statement is too heavy, maybe I should do it in a totally different way.
I think you have perhaps over complicated things.
You could do this (assuming I have understood your requirements correctly) like so:
WITH ttr AS (SELECT rltd_team_id,
COUNT(*) is_master
FROM team_team_rel
AND CODE = 'Double'
GROUP BY rltd_team_id),
trr AS (SELECT team_id,
COUNT(*) is_agent
FROM team_rol_rel
GROUP BY team_id)
pacts AS (SELECT trr1.team_id,
COUNT(*) num_pacts
FROM team_rol_rel trr1
INNER JOIN team_rol_pol_rel trpr ON (trr1.t_rol_rel_id = trpr.p_rol_rel_id)
INNER JOIN perso_pol_sta_rel ppsr ON (trpr.p_pol_id = ppsr.p_pol_id
WHERE trr1.rol_cd IN ('1', '2')
AND ppsr.st_cd = 'A'
GROUP BY trr1.team_id)
SELECT t.id pkey_src_object,
t.modf_dat update_date,
t.modf_usr updated_by,
p.first_nam first_name,
ttr.is_master,
trr.is_agent,
pacts.num_pacts
FROM team t
LEFT OUTER JOIN perso p ON t.id = p.team_id
LEFT OUTER JOIN ttr ON t.party_pty_id = ttr.rltd_team_id
LEFT OUTER JOIN trr ON t.party_pty_id = trr.team_id
LEFT OUTER JOIN pacts ON t.pkey_src_object = pacts.team_id;
N.B. untested, since you didn't provide any test data.

SQL - left join generate duplicates

I have code to select some applications but LEFT JOIN is creating duplicates.
Question: How to get rid of duplicates generated by
LEFT JOIN
attachments as att
ON
(a.ssn = att.ssn AND att.doc_type = 'id_copy' AND att.source = 'cpt3')
My Work:
I am considering SELECT DISTINCT or GROUP BY but, can't figure out where to put them.
This is the query:
SELECT
a.*, c.code, l.who, l.locked_time, att.id AS attnew,
( SELECT
COUNT(*)
FROM
applications as a2
WHERE
a2.approved = 'Y'
AND
a2.paid = 'Y'
AND
a2.paid_back = 'Y'
AND
a2.ssn = a.ssn
) AS previous_apps
FROM
applications as a
LEFT JOIN
locked_by as l
USING(id)
LEFT JOIN
campaign_codes as c
ON
c.id = a.campaign
LEFT JOIN
attachments as att
ON
(a.ssn = att.ssn AND att.doc_type = 'id_copy' AND att.source = 'cpt3')
WHERE
a.closed='N'
AND
a.paid = 'N'
ORDER BY
a.arrived_date
DESC
Use GROUP BY
to avoid duplicates. In your case:
...
WHERE
a.closed='N'
AND
a.paid = 'N'
GROUP BY
a.id
ORDER BY
a.arrived_date
DESC
If you want to make an one to one relation to avoid duplicates and att.id is the same for each att.ssn or you need only one (MAX,MIN,..ANY?) att.id. Try this:
LEFT JOIN
(SELECT ssn,
MAX(id) as id,
FROM attachments
WHERE doc_type = 'id_copy' AND source = 'cpt3'
GROUP BY ssn
)as att
ON
(a.ssn = att.ssn)