Rewrite tsql select statement without sub-sub selects - tsql

I'd like to rewrite the following select statement without the sub selects; while it works at the moment as it is it only works if there's data, when one of the sub selects doesn't return data I get an error
Each GROUP BY expression must contain at least one column that is not an outer reference.
This is the select:
SELECT COUNT(DISTINCT ( PROMSID )) AS Volume ,
( SELECT CAST(CAST(COUNT(DISTINCT ( PROMSID )) AS DECIMAL(8, 2))
/ ( SELECT COUNT(DISTINCT RES.Branch)
FROM tblPROMsExportSummary AS PES
INNER JOIN TVF_GetRelevantScorecards(#ProcedureID, 82, #StartDate, #EndDate) AS RES ON RES.PROMSID = PES.PROMSID
INNER JOIN tblUploadedScorecards AS UPL ON PES.PROMSID = UPL.PEMSID
WHERE RES.[Month] = TVF.MonthValue
GROUP BY TVF.MonthValue
) AS DECIMAL(8, 2)) AS PCTAverage
FROM #RelevantSummaryPCT AS PCT
WHERE PCT.[Month] = TVF.[MonthValue]
GROUP BY TVF.[MonthValue]
) AS PCTAverage ,
TVF.ShortMonth AS [Month]
FROM #RelevantSummary AS RS
RIGHT OUTER JOIN TVF_Months(#StartDate, #EndDate) AS TVF ON TVF.MonthValue = RS.[Month]
GROUP BY TVF.[MonthName] ,
TVF.[MonthValue] ,
TVF.ShortMonth ,
TVF.DisplayOrder
ORDER BY TVF.DisplayOrder
What I am looking to achieve is a a single set of data from 2 temp tables which store results for different levels of reporting. The Volume column is the volume of results for 'my group' and the PCTAverage is the volume of results across all groups. The selects for those 2 temp tables:
SELECT DISTINCT
PES.FKProcedureID ,
PES.PROMSID ,
UPL.PKID AS UploadID ,
MONTH(UPL.ShopDate) AS [Month]
INTO #RelevantSummary
FROM tblPROMsExportSummary AS PES
INNER JOIN TVF_GetRelevantScorecards(#ProcedureID, #AreaID, #StartDate, #EndDate) AS RES ON RES.PROMSID = PES.PROMSID
INNER JOIN tblUploadedScorecards AS UPL ON PES.PROMSID = UPL.PEMSID
-- also get them for all PCTs, #AreaID hardcoded to 82
SELECT DISTINCT
PES.FKProcedureID ,
PES.PROMSID ,
UPL.PKID AS UploadID ,
MONTH(UPL.ShopDate) AS [Month]
INTO #RelevantSummaryPCT
FROM tblPROMsExportSummary AS PES
INNER JOIN TVF_GetRelevantScorecards(#ProcedureID, 82, #StartDate, #EndDate) AS RES ON RES.PROMSID = PES.PROMSID
INNER JOIN tblUploadedScorecards AS UPL ON PES.PROMSID = UPL.PEMSID

I'm not as good as to rewrite the sub queries, but based on what you wrote :
I'd like to rewrite the following select statement without the sub selects;
while it works at the moment as it is it only works if there's data, when one of the sub selects doesn't return data I get an error
I wonder if COALESCE could do the trick for your problem.

Using derived tables is what I was after, in the example above it can be achieved like this:
SELECT * FROM (
SELECT DISTINCT
PES.FKProcedureID ,
PES.PROMSID ,
UPL.PKID AS UploadID ,
MONTH(UPL.ShopDate) AS [Month]
INTO #RelevantSummary
FROM tblPROMsExportSummary AS PES
INNER JOIN TVF_GetRelevantScorecards(#ProcedureID, #AreaID, #StartDate, #EndDate) AS RES ON RES.PROMSID = PES.PROMSID
INNER JOIN tblUploadedScorecards AS UPL ON PES.PROMSID = UPL.PEMSID ) AS T1
INNER JOIN (
SELECT DISTINCT
PES.FKProcedureID ,
PES.PROMSID ,
UPL.PKID AS UploadID ,
MONTH(UPL.ShopDate) AS [Month]
INTO #RelevantSummaryPCT
FROM tblPROMsExportSummary AS PES
INNER JOIN TVF_GetRelevantScorecards(#ProcedureID, 82, #StartDate, #EndDate) AS RES ON RES.PROMSID = PES.PROMSID
INNER JOIN tblUploadedScorecards AS UPL ON PES.PROMSID = UPL.PEMSID ) AS T2
ON T1.PROMSID = T2.PROMSID
To quote directly from the 4guys post
What we are doing is first getting the result set from our derived table (the SELECT statement in the FROM clause). Once we have that resultset, it is as though it was a table in itself. We then perform the SELECT on the derived table, returning our results! You can find another example of using derived tables here on 4GuysFromRolla.com in the article Obtaining Ranked Values from a Table page.
Though my final select looks more like this:
SELECT ISNULL(Volume, 0) AS Volume ,
ISNULL(PCTAverage, 0) AS PCTAverage ,
ShortMonth AS [Month] ,
DisplayOrder
FROM ( SELECT COUNT(DISTINCT ( PROMSID )) AS Volume ,
RS.YearMonth
FROM #RelevantSummary AS RS
GROUP BY YearMonth ) AS RS
INNER JOIN ( SELECT CAST(CAST(COUNT(PROMSID) AS DECIMAL(8, 3))
/ ( SELECT ISNULL(COUNT(DISTINCT RES.Branch), 1)
FROM tblPROMsExportSummary AS PES
INNER JOIN TVF_GetRelevantScorecards(#ProcedureID, #RootReportLevelID, #ReportLevelID, #StartDate,
#EndDate) AS RES ON RES.PROMSID = PES.PROMSID
INNER JOIN tblUploadedScorecards AS UPL ON PES.PROMSID = UPL.PEMSID
WHERE RES.YearMonth = PCT.YearMonth
GROUP BY RES.YearMonth ) AS DECIMAL(8, 3)) AS PCTAverage ,
YearMonth
FROM #RelevantSummaryPCT AS PCT
GROUP BY YearMonth ) AS PCT ON RS.YearMonth = PCT.YearMonth
RIGHT OUTER JOIN ( SELECT *
FROM dbo.TVF_Months(#StartDate, #EndDate) ) AS TVF ON TVF.DisplayOrder = RS.YearMonth

Related

PostgreSQL pass value into INNER JOIN

PostgreSQL 11
How to pass o.create_date value into INNER JOIN? I need Max ID before o.create_date
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_invenotry oi on o.id = oi.order_id
LEFT JOIN ax_inventory i on i.id = oi.inventory_id
LEFT JOIN ax_suppliers s on s.id = o.supplier_id
INNER JOIN ax_supplier_price sp ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
INNER JOIN
(
SELECT inventory_id,
max(id) id
FROM ax_supplier_price
WHERE create_date <= o.create_date
GROUP BY inventory_id
) lsp ON (sp.id = lsp.id)
WHERE o.store_id = 13
AND o.supplier_id = 35
GROUP BY o.id, o.create_date
ORDER BY o.id
You could use the LATERAL join mechanism to make it work:
WITH ax_order AS (
SELECT *
FROM (VALUES (1, '2000-1-1'::date, 1, 1)) as x(id, create_date, store_id, supplier_id)
), ax_order_inventory AS (
SELECT *
FROM (VALUES (1, 2, 4)) as x(order_id, inventory_id, quantity)
), ax_supplier_price AS (
SELECT *
FROM (VALUES (1, 2, 1, 10, '1999-12-31'::date)) as x(id, inventory_id, supplier_id, price, create_date)
)
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_inventory oi on o.id = oi.order_id
INNER JOIN ax_supplier_price sp ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
INNER JOIN LATERAL
(
SELECT inventory_id,
max(lsp.id) id
FROM ax_supplier_price lsp
WHERE sp.create_date <= o.create_date
GROUP BY inventory_id
) lsp ON sp.id = lsp.id
GROUP BY o.id, o.create_date
ORDER BY o.id
I deleted some JOINs that were not strictly necessary and mocked your data as well as I could see. Note, however, that you could also use a WHERE clause to find it - which should be more efficient:
WITH ax_order AS (
SELECT *
FROM (VALUES (1, '2000-1-1'::date, 1, 1)) as x(id, create_date, store_id, supplier_id)
),
ax_order_inventory AS (
SELECT *
FROM (VALUES (1, 2, 4)) as x(order_id, inventory_id, quantity)
),
ax_supplier_price AS (
SELECT *
FROM (VALUES (1, 2, 1, 10, '1999-12-31'::date)) as x(id, inventory_id, supplier_id, price, create_date)
)
SELECT o.id,
o.create_date date,
sum(oi.quantity) qty,
sum(oi.quantity * sp.price) total
FROM ax_order o
LEFT JOIN ax_order_inventory oi on o.id = oi.order_id
INNER JOIN ax_supplier_price sp
ON (sp.inventory_id = oi.inventory_id and sp.supplier_id = o.supplier_id)
WHERE sp.id =
(
-- NOTE: no GROUP BY necessary!
SELECT max(lsp.id) id
FROM ax_supplier_price lsp
WHERE sp.create_date <= o.create_date
AND lsp.inventory_id = sp.inventory_id
)
GROUP BY o.id, o.create_date
ORDER BY o.id

Select the last record for the date and time columns

I need to select the last record in the academic table which has two columns for date and time. When I run the query I get an error. Only one expression can be specified in the select list when the subquery is not introduced with EXISTS.
USE PCUnitTest
SELECT C.ACCOUNTNO, C.CONTACT, C.LASTNAME, C.KEY4, A.PEOPLE_ID, A.APP_STATUS, A.APP_DECISION, A.REVISION_DATE, A.REVISION_TIME
FROM ACADEMIC AS A INNER JOIN
GM.dbo.CONTACT1 AS C ON A.PEOPLE_ID = C.KEY4
WHERE A.REVISION_DATE = (SELECT TOP (1) REVISION_DATE, REVISION_TIME, PEOPLE_CODE, PEOPLE_ID, PEOPLE_CODE_ID, ACADEMIC_YEAR, ACADEMIC_TERM, ACADEMIC_SESSION, PROGRAM, DEGREE, CURRICULUM
FROM PCUnitTest.dbo.ACADEMIC
ORDER BY REVISION_DATE DESC, REVISION_TIME DESC)
You can Join the query you are using in the where
USE PowerCampusUnitTest
SELECT C.ACCOUNTNO, C.CONTACT, C.LASTNAME, C.KEY4, A.PEOPLE_ID, A.APP_STATUS, A.APP_DECISION, A.REVISION_DATE, A.REVISION_TIME
FROM ACADEMIC AS A
INNER JOIN GoldMineUnitTest.dbo.CONTACT1 AS C
ON A.PEOPLE_ID = C.KEY4
INNER JOIN (
SELECT TOP 1 A2.REVISION_DATE,A2.REVISION_TIME FROM PowerCampusUnitTest.dbo.ACADEMIC A2
ORDER BY REVISION_DATE DESC, REVISION_TIME DESC
)AS A2
ON A.REVISION_DATE = A2.REVISION_DATE AND A.REVISION_TIME = A2.REVISION_TIME
Use ROW_NUMBER()
USE PCUnitTest
SELECT
R.ACCOUNTNO, R.CONTACT, R.LASTNAME, R.KEY4, R.PEOPLE_ID, R.APP_STATUS, R.APP_DECISION, R.REVISION_DATE, R.REVISION_TIME
FROM
(
SELECT C.ACCOUNTNO, C.CONTACT, C.LASTNAME, C.KEY4, A.PEOPLE_ID, A.APP_STATUS, A.APP_DECISION, A.REVISION_DATE, A.REVISION_TIME
,ROW_NUMBER() OVER (ORDER BY A.REVISION_DATE DESC, A.REVISION_TIME DESC) RN
FROM ACADEMIC AS A INNER JOIN
GMUnitTest.dbo.CONTACT1 AS C ON A.PEOPLE_ID = C.KEY4
) R
WHERE RN=1
If you want to get the latest row for each PEOPLE_ID, then add PARTITION BY
SELECT
R.ACCOUNTNO, R.CONTACT, R.LASTNAME, R.KEY4, R.PEOPLE_ID, R.APP_STATUS, R.APP_DECISION, R.REVISION_DATE, R.REVISION_TIME
FROM
(
SELECT C.ACCOUNTNO, C.CONTACT, C.LASTNAME, C.KEY4, A.PEOPLE_ID, A.APP_STATUS, A.APP_DECISION, A.REVISION_DATE, A.REVISION_TIME
,ROW_NUMBER() OVER (PARTITION BY A.PEOPLE_ID ORDER BY A.REVISION_DATE DESC, A.REVISION_TIME DESC) RN
FROM ACADEMIC AS A INNER JOIN
GMUnitTest.dbo.CONTACT1 AS C ON A.PEOPLE_ID = C.KEY4
) R
WHERE RN=1

Bad performance for muli joined sub-queries

Could someone help me on this query. When generating the related report through web application it times out due to response time taking over 30seconds(standard http request time out).
select c.counterparty_shortname AS [Réference]
,cty.counterparty_type_name AS [Type ref]
,t.transaction_shortname AS [transaction_shortname]
,mitigant_shortname
,(SELECT ISNULL(SUM(ISNULL(tce.outstanding_amount,0)),0)
from transaction_credit_event tce
where tce.transaction_id=t.transaction_id) AS [Montant impayé]
,(select count(t1.transaction_id)
from [transaction] t1
where t1.counterparty_id=c.counterparty_id) AS [Nbre affaire]
,(select isnull(count(tce.credit_event_id),0)
from transaction_credit_event tce
where tce.transaction_id=t.transaction_id
and isnull(tce.outstanding_amount,0)>0
and tce.credit_event_type_id=51) AS [nbr impaye]
,TT.transaction_type_name AS [Type Produit]
,isnull(cm1.value1_text,'') AS [type garantie]
,isnull(cm2.value1_text,'') AS [marque]
,isnull(cm3.value1_text,'') AS [modele]
,(select top 1 tmp1.payment_posting_date
from (select pp.payment_posting_date
,tce.transaction_id
FROM payment_posting pp
inner JOIN transaction_credit_event tce
ON pp.credit_event_id=tce.credit_event_id) tmp1
where tmp1.transaction_id=t.transaction_id
order by tmp1.payment_posting_date desc) AS [Date dernier paiement]
,fate_shortname AS [sort]
,raf.recovery_action_fate_id
,ISNULL(t.outstanding_amount,0) AS [CRD]
,1 AS [ID]
,(select isnull(count(tce.credit_event_id),0)
from transaction_credit_event tce,[transaction] tt
where tce.transaction_id=tt.transaction_id
and tt.counterparty_id=c.counterparty_id
and isnull(tce.outstanding_amount,0)>0
and tce.credit_event_type_id=51) AS [nbr impaye tiers]
,convert(date,dispatch_start_date,103) AS [date debut]
,convert(date,dispatch_end_date,103) AS [date fin]
,c.counterparty_type_id
,t.transaction_type_id
from counterparty c
inner join wf_task_dispatch w on w.item_id=c.counterparty_id
inner join [transaction] t on c.counterparty_id=t.counterparty_id
LEFT join transaction_recovery tr on tr.counterparty_id=c.counterparty_id and tr.transaction_recovery_id=(select top 1 transaction_recovery_id from transaction_recovery where counterparty_id=c.counterparty_id order by idate desc)
LEFT join recovery_action_fate raf on raf.recovery_action_fate_id=tr.recovery_action_fate_id
left join counterparty_type cty on cty.counterparty_type_id=c.counterparty_type_id
left join [transaction_type] TT on t.transaction_type_id = TT.transaction_type_id
inner join mitigant_transaction mt on mt.transaction_id=t.transaction_id and mt.ddate is null
inner join mitigant m on m.mitigant_id=mt.mitigant_id and mitigant_screen='asset' and m.ddate is null
left join constant_matrix cm1 on cm1.criteria1_text=m.regulatory_mitigant_type and cm1.constant_matrix_shortname='CAIN' and cm1.ddate is null
left join constant_matrix cm2 on cm2.criteria1_text=m.valuation_frequency and cm2.constant_matrix_shortname='MARQ' and cm2.ddate is null
left join constant_matrix cm3 on cm3.criteria1_text=m.valuation_source and cm3.constant_matrix_shortname='GMOD' and cm3.ddate is null
where (select [dbo].FN_GetPhase)=81

Need to optimize the query and rewrite it as it taking a lot of time on running on server

I have this query and taking so much time to run , is there any way i can improve it , with creating any new views ,,, i can`t create temp db tables as they are avoid by DBA because of load on server
SELECT DISTINCT o.email AS eml_addr,
UPPER(max(FORMAT(cl.clicktime, 'dd-MMM-yyyy'))) AS lst_clk_mnth,
UPPER(max(FORMAT(o.opentime, 'dd-MMM-yyyy'))) AS lst_opn_mnth
FROM [open] o WITH (NOLOCK)
INNER JOIN view_mailing m WITH (NOLOCK)
ON (o.mailingid = m.mailingid)
INNER JOIN view_campaign c WITH (NOLOCK)
ON (c.campaignid = m.campaignid)
LEFT JOIN click cl WITH (NOLOCK)
ON (
o.mailingid = cl.mailingid
AND o.email = cl.email
)
WHERE c.clientid IN (
SELECT clientid
FROM client
WHERE sameclient IN (
SELECT sameclient
FROM client
WHERE clientid IN (219)
)
)
AND CONVERT(VARCHAR(8), cast(o.opentime AS DATETIME), 112) & gt;= 20130826
GROUP BY o.email;
Thanks
I don't see the purpose of both a distinct and group by
A derived table does not use indexes
Date in a varchar is not optimal
SELECT o.email AS eml_addr,
UPPER(max(FORMAT(cl.clicktime, 'dd-MMM-yyyy'))) AS lst_clk_mnth,
UPPER(max(FORMAT(o.opentime, 'dd-MMM-yyyy'))) AS lst_opn_mnth
FROM [open] o WITH (NOLOCK)
LEFT JOIN click cl WITH (NOLOCK)
ON o.mailingid = cl.mailingid
AND o.email = cl.email
JOIN view_mailing m WITH (NOLOCK)
ON o.mailingid = m.mailingid
JOIN view_campaign c WITH (NOLOCK)
ON c.campaignid = m.campaignid
join client with (NOLOCK)
on c.clientid = client.sameclient
and client.clientid IN (219)
WHERE CONVERT(VARCHAR(8), cast(o.opentime AS DATETIME), 112) & gt;= 20130826
GROUP BY o.email;

Error converting data type varchar to float when using Top clause in sql query

Why I get converting error when I use top clause in my query but when I use select * in my query everything is ok.
I use SQL server 2000
I use a view that is created from below code
select sum(g.qty) as qty,g.PartCode,g.PartName,g.arz,g.t,g.OrdNo,max(g.id) as id,g.Val from
(SELECT sum(iv.FinalQty) AS qty, p.PartCode, p.PartName, CAST(RIGHT(p.PartCode, 4) AS float) AS arz,case when isnumeric(LEFT(RIGHT(p.PartCode, 7), 3))=1 then CAST(LEFT(RIGHT(p.PartCode, 7), 3) AS float) / 100 else CAST(LEFT(RIGHT(p.PartCode, 7), 4) AS float)/100 end AS t, ord.OrdNo,
id.id,ctrl.val
FROM INV.InvVchHdr AS hv WITH (nolock) INNER JOIN
INV.InvVchItm AS iv WITH (nolock) ON hv.VchHdrID = iv.VchHdrRef INNER JOIN
inv.Part p WITH (nolock) ON p.Serial = iv.PartRef INNER JOIN
INV.InvRqstItm AS i WITH (nolock) ON i.RqstItmID = iv.RefNum INNER JOIN
INV.InvRqstHdr AS h WITH (nolock) ON h.RqstHdrID = i.HdrRef INNER JOIN
PRD.PrdOrdPlan AS po WITH (nolock) ON po.OrdPlnId = h.OrdPlnBase INNER JOIN
PRD.PrdOrdItem AS oi WITH (nolock) ON oi.OrdItmId = po.OrdItmRef INNER JOIN
PRD.PrdOrder AS ord WITH (nolock) ON ord.OrdID = oi.OrderRef JOIN
inv.InvVchItmCtrl ctrl WITH (nolock) ON ctrl.VchItmRef = iv.VchItmID
join USR.idgen_coil_trace id WITH (nolock) on id.vchitmid=iv.VchItmID
WHERE (hv.VchType = 51) AND (iv.BaseVchType <> 0) and iv.VchItmID>981336159
and isnumeric(LEFT(RIGHT(p.PartCode, 7), 3))=1
AND hv.VchHdrID IN
(SELECT max(i.vchhdrref)
FROM inv.InvVchItm i WITH (nolock) JOIN
inv.InvVchItmCtrl c WITH (nolock) ON c.VchItmRef = i.VchItmID
WHERE i.VchType = 51
GROUP BY i.PartRef, c.Val)
GROUP BY p.PartCode, p.PartName, CAST(RIGHT(p.PartCode, 4) AS float)
, CAST(LEFT(RIGHT(p.PartCode, 7), 3) AS float) / 100
, ord.OrdNo, ctrl.Val,id.id) g
--join USR.idgen_coil_trace id on id.vchitmid=g.VchItmID
group by g.PartCode, g.PartName, g.arz
, g.t, g.OrdNo, g.Val
UNION
select sum(g.qty),g.PartCode,g.PartName,g.SizeW,g.SizeH,g.OrdNo,max(g.id),g.Val from(SELECT sum(iv.FinalQty) AS qty, p.PartCode, p.PartName, cp.SizeW, cp.Sizeh, ord.OrdNo,id.id, ctrl.val
FROM INV.InvVchHdr AS hv WITH (nolock) INNER JOIN
INV.InvVchItm AS iv WITH (nolock) ON hv.VchHdrID = iv.VchHdrRef INNER JOIN
INV.Part AS p WITH (nolock) ON p.Serial = iv.PartRef INNER JOIN
INV.InvRqstItm AS i WITH (nolock) ON i.RqstItmID = iv.RefNum INNER JOIN
INV.InvRqstHdr AS h WITH (nolock) ON h.RqstHdrID = i.HdrRef INNER JOIN
PRD.PrdOrdPlan AS po WITH (nolock) ON po.OrdPlnId = h.OrdPlnBase INNER JOIN
PRD.PrdOrdItem AS oi WITH (nolock) ON oi.OrdItmId = po.OrdItmRef INNER JOIN
PRD.PrdOrder AS ord WITH (nolock) ON ord.OrdID = oi.OrderRef JOIN
inv.InvVchItmCtrl ctrl WITH (nolock) ON ctrl.VchItmRef = iv.VchItmID JOIN
inv.PartCmplmnt cp WITH (nolock) ON cp.PartRef = p.Serial
join USR.idgen_coil_trace id WITH (nolock) on id.vchitmid=iv.VchItmID
WHERE (hv.VchType = 57) AND (iv.BaseVchType <> 0) and iv.VchItmID>981336159
AND PO.PartRef IN (SELECT SERIAL FROM INV.Part P WHERE P.PartName LIKE '%لاف%')
GROUP BY p.PartCode, p.PartName, cp.SizeW, cp.Sizeh, ord.OrdNo,id.id, ctrl.Val)g
--join USR.idgen_coil_trace id on id.vchitmid=g.VchItmID
group by g.PartCode, g.PartName, g.SizeW
, g.SizeH, g.OrdNo, g.Val
UNION
--SELECT *FROM usr.aghili WITH (nolock)
--UNION
--SELECT *
--FROM usr.moradi WITH (nolock)
SELECT qty, PartCode, PartName, arz, t, OrdNo, id, val FROM USR.COIL_TRACE_BAK WITH (nolock)
union
select qty,PartCode,PartName,arz,t,OrdNo,id,Val from usr.unregister_coil_trace WITH (nolock)
this query is correct > select * from usr.coil_trace
this query is not correct > select top 100 * from usr.coil_trace
Top clause should work in sql server 2000.
Though I do not have sql 2000 with me but this link should help you.
Also have a look at answers at this stackover flow link