Including CTE within a query - sql

I have the following code which works perfectly.
What I need to do is include it in a query using the result of the CTE as a column in the query result but I cannot work out the way to include it.
Any ideas please?
What I would like is effectively this:
select a,
b,
c,
d,
WITH invoicedates AS (
SELECT
ROW_NUMBER() OVER (ORDER BY Inv_Date DESC) AS RowNumber,
inv_Date, INVIT_PARTNO
FROM Invoices join InvoiceItems on invit_invno = inv_no
WHERE invit_partno = stock_no and inv_canind <> 'Y' and inv_date >= DATEADD(yy, -1, getdate())
)
SELECT
AVG(DATEDIFF(DD, O2.Inv_Date, O1.Inv_Date)) AS AverageFrequency
FROM invoicedates O1
LEFT JOIN invoicedates O2
ON O2.RowNumber = O1.RowNumber + 1
from stock where ..........
to give a resulting output of a b c d result

You should be able to just reorder how you're using the CTE:
; WITH invoicedates (RowNumber, inv_Date, INVIT_PARTNO) AS (
SELECT
ROW_NUMBER() OVER (ORDER BY Inv_Date DESC) AS RowNumber,
inv_Date, INVIT_PARTNO
FROM Invoices join InvoiceItems on invit_invno = inv_no
WHERE invit_partno = stock_no and inv_canind <> 'Y' and inv_date >= DATEADD(yy, -1, getdate())
)
select a,
b,
c,
d,
AVG(DATEDIFF(DD, O2.Inv_Date, O1.Inv_Date)) AS AverageFrequency
FROM invoicedates O1
LEFT JOIN invoicedates O2
ON O2.RowNumber = O1.RowNumber + 1

Related

Avoid SQL Pivot returning duplicate rows

I have the following SQL script which returns duplciate values in PIVOT. How do I combine those duplicate records to one row.
Please check the below image for the results set.
SELECT *
FROM (SELECT X.stockcode,
X.description,
X.pack,
X.location,
X.lname,
X.qty,
Y.stockcode AS StockCode2,
y.periodname,
Y.months,
Y.saleqty
FROM (SELECT dbo.stock_items.stockcode,
dbo.stock_items.description,
dbo.stock_items.pack,
dbo.stock_loc_info.location,
dbo.stock_locations.lname,
dbo.stock_loc_info.qty
FROM dbo.stock_locations
INNER JOIN dbo.stock_loc_info
ON dbo.stock_locations.locno = dbo.stock_loc_info.location
LEFT OUTER JOIN dbo.stock_items
ON dbo.stock_loc_info.stockcode = dbo.stock_items.stockcode
WHERE ( dbo.stock_items.status = 's' )) AS X
LEFT OUTER JOIN (SELECT dbo.dr_invlines.stockcode,
( 12 + Datepart(month, Getdate()) - Datepart(month, dbo.dr_trans.transdate) ) % 12 + 1 AS Months,
Sum(dbo.dr_invlines.quantity) AS SaleQty,
dbo.period_status.periodname
FROM dbo.dr_trans
INNER JOIN dbo.period_status
ON dbo.dr_trans.period_seqno = dbo.period_status.seqno
LEFT OUTER JOIN dbo.stock_items AS STOCK_ITEMS_1
RIGHT OUTER JOIN dbo.dr_invlines
ON STOCK_ITEMS_1.stockcode = dbo.dr_invlines.stockcode
ON dbo.dr_trans.seqno = dbo.dr_invlines.hdr_seqno
WHERE ( STOCK_ITEMS_1.status = 'S' )
AND ( dbo.dr_trans.transtype IN ( 1, 2 ) )
AND ( dbo.dr_trans.transdate >= Dateadd(m, -6, Getdate()) )
GROUP BY dbo.dr_invlines.stockcode,
Datepart(month, dbo.dr_trans.transdate),
dbo.period_status.periodname) AS Y
ON X.stockcode = Y.stockcode) z
PIVOT (Sum(saleqty) FOR [months] IN ([1],[2],[3],[4],[5],[6])) AS pivoted
EDIT: I missed the root-cause of your issue being the inclusion of the periodname column causing the percieved duplication. I am leaving this in place as general solution showing CTE usage, because it could still be useful if you then want to do extra filtering/transformation of your pivot results
One way is to take the results of the pivot query and run it through a SELECT DISTINCT query.
An example of wrapping your pivot query as a CTE and using it to feed a SELECT DISTINCT below (please note: untested, but parses as valid in my SSMS)
WITH PivotResults_CTE (
stockcode,
description,
pack,
location,
lname,
qty,
StockCode2,
periodname,
months,
saleqty
)
AS (
SELECT *
FROM (
SELECT X.stockcode
,X.description
,X.pack
,X.location
,X.lname
,X.qty
,Y.stockcode AS StockCode2
,y.periodname
,Y.months
,Y.saleqty
FROM (
SELECT dbo.stock_items.stockcode
,dbo.stock_items.description
,dbo.stock_items.pack
,dbo.stock_loc_info.location
,dbo.stock_locations.lname
,dbo.stock_loc_info.qty
FROM dbo.stock_locations
INNER JOIN dbo.stock_loc_info ON dbo.stock_locations.locno = dbo.stock_loc_info.location
LEFT OUTER JOIN dbo.stock_items ON dbo.stock_loc_info.stockcode = dbo.stock_items.stockcode
WHERE (dbo.stock_items.STATUS = 's')
) AS X
LEFT OUTER JOIN (
SELECT dbo.dr_invlines.stockcode
,(12 + Datepart(month, Getdate()) - Datepart(month, dbo.dr_trans.transdate)) % 12 + 1 AS Months
,Sum(dbo.dr_invlines.quantity) AS SaleQty
,dbo.period_status.periodname
FROM dbo.dr_trans
INNER JOIN dbo.period_status ON dbo.dr_trans.period_seqno = dbo.period_status.seqno
LEFT OUTER JOIN dbo.stock_items AS STOCK_ITEMS_1
RIGHT OUTER JOIN dbo.dr_invlines ON STOCK_ITEMS_1.stockcode = dbo.dr_invlines.stockcode ON dbo.dr_trans.seqno = dbo.dr_invlines.hdr_seqno WHERE (STOCK_ITEMS_1.STATUS = 'S')
AND (
dbo.dr_trans.transtype IN (
1
,2
)
)
AND (dbo.dr_trans.transdate >= Dateadd(m, - 6, Getdate()))
GROUP BY dbo.dr_invlines.stockcode
,Datepart(month, dbo.dr_trans.transdate)
,dbo.period_status.periodname
) AS Y ON X.stockcode = Y.stockcode
) z
PIVOT(Sum(saleqty) FOR [months] IN (
[1]
,[2]
,[3]
,[4]
,[5]
,[6]
)) AS pivoted
)
SELECT DISTINCT *
FROM
PivotResults_CTE
;
Also note, your sql included in the above may look slightly different to your original but that is only because i ran it through a reformatter to ensure i understood the structure of it.
In other words, the basic CTE wrapper for your pivot query is:
WITH PivotResults_CTE (
Field1,
Field2,
...
)
AS (
YOUR_PIVOT_QUERY_HERE
)
SELECT DISTINCT *
FROM
PivotResults_CTE
;

SQL : Get Column table twice with differents clause where

I try to get the same column in the same table twice with different clauses :
My query:
SELECT
*
FROM
(SELECT TOP 10
CONVERT(DATE, attemptdate) AS Date,
Max(currentcount) AS A
FROM
logintracking
INNER JOIN
maxuser ON logintracking.loginid = maxuser.loginid
INNER JOIN
site ON site.siteid = maxuser.defsite
WHERE
attemptdate BETWEEN #dateDebut AND #dateFin
AND logintracking.clientaddr IN ('10.118.254.21', '10.118.254.156')
GROUP BY
CONVERT(DATE, attemptdate)
ORDER BY
CONVERT(DATE, attemptdate) ASC
) AS T1,
(SELECT TOP 10
CONVERT(DATE, attemptdate) AS Date,
MAX(currentcount) AS B
FROM
logintracking
INNER JOIN
maxuser ON logintracking.loginid = maxuser.loginid
INNER JOIN
site ON site.siteid = maxuser.defsite
WHERE
attemptdate BETWEEN #dateDebut AND #dateFin
AND logintracking.clientaddr = '10.118.254.35'
GROUP BY
CONVERT(DATE, attemptdate)
ORDER BY
CONVERT(DATE, attemptdate) ASC) AS T2
Result:
Desired result:
My objective is to get the same column 'max(currentcount)' twice and to apply different where clauses so to get two columns named (A & B), and i need also to show the date in the first column, can you please help ? Thanks
Since the only difference between A and B is logintracking.clientaddr, you can put that condition within a CASE statement within the MAX function:
SELECT CONVERT(DATE, attemptdate) AS Date,
MAX(CASE WHEN logintracking.clientaddr IN ( '10.118.254.21', '10.118.254.156' ) THEN currentcount END) AS A,
MAX(CASE WHEN logintracking.clientaddr IN ( '10.118.254.35' ) THEN currentcount END) AS B
FROM logintracking
INNER JOIN maxuser
ON logintracking.loginid = maxuser.loginid
INNER JOIN site
ON site.siteid = maxuser.defsite
WHERE attemptdate BETWEEN #dateDebut AND #dateFin
GROUP BY CONVERT(DATE, attemptdate)
ORDER BY CONVERT(DATE, attemptdate) ASC

Use of Analytical Funtions and Keep clause

I have a lenghtly query that can be shorten with the correct functionally (I beleive). Can we use existing functions such as Max Min Keep to make this query more efficient? My entire query is posted below.
For example: Can we remove the CTEs and use analytical functions such as max and min This would also elimate ranks and several joins
SQL:
WITH LAST_VALUE_BEFORE_START_DT AS (
SELECT DISTINCT * FROM(
SELECT
P.CL_ID,
HISTORYID,
H.MENT_DT,
H.ROLE AS MAX_ROLE,
H.PM_ID AS MAX_P_ID,
DENSE_RANK() OVER (PARTITION BY P.CL_ID ORDER BY H.MENT_DT DESC )AS RNK
FROM MANAGER_HISTORY H
INNER JOIN CP CCP ON H.CLIID = CCP.CLIID
INNER JOIN PROGRAM CP ON PROGRAMID = CP.PROGRAMID
WHERE 1=1
AND CP.TYPEID IN (13,200,11001)
AND H.ROLE = 'RED'
AND H.MENT_DT < START_DT
--AND P.CL_ID = 920917
)LAST_VALUE_BEFORE_START_DT_RNK
WHERE 1=1
AND RNK =1
)
,MIN_VALUE_BETWEEN_PROGRAM AS (
SELECT * FROM(
SELECT DISTINCT
P.CL_ID,
HISTORYID,
TRUNC(H.MENT_DT) AS MENT_DT,
H.ROLE AS MIN_ROLE,
H.PM_ID AS MIN_PM_ID,
DENSE_RANK() OVER (PARTITION BY P.CL_ID ORDER BY H.MENT_DT)AS RNK
FROM MANAGER_HISTORY H
INNER JOIN CP CCP ON H.CLIID = CCP.CLIID
INNER JOIN PROGRAM CP ON PROGRAMID = CP.PROGRAMID
WHERE 1=1
AND CP.TYPEID IN (13,200,11001)
AND H.ROLE = 'RED'
AND H.PM_ID IS NOT NULL
AND TRUNC(H.MENT_DT) BETWEEN TRUNC(START_DT) AND NVL(END_DT,SYSDATE)
--AND P.CL_ID = 920917
) MIN_VALUE_BETWEEN_PROGRAM_RNK
WHERE 1=1
AND RNK =1
)
SELECT * FROM (
SELECT
X.*,
DENSE_RANK() OVER (PARTITION BY CL_ID ORDER BY FIRST_ASSGN_DT,MENT_DT ) AS RNK
FROM(
SELECT DISTINCT
C.CL_ID,
P.CL_ID,
CP.PROGRAM,
START_DT,
END_DT,
H.ROLE,
H.MENT_DT,
H.PM_ID,
LVBS.MAX_ROLE,
LVBS.MAX_P_ID,
MVBP.MIN_ROLE,
MVBP.MIN_PM_ID
,CASE
WHEN H.MENT_DT < START_DT AND LVBS.MAX_ROLE = 'RED' AND LVBS.MAX_P_ID IS NOT NULL THEN TRUNC(START_DT)
WHEN H.MENT_DT BETWEEN START_DT AND NVL(END_DT,SYSDATE) AND H.ROLE = 'RED' AND H.PM_ID IS NOT NULL
THEN MVBP.MENT_DT
ELSE NULL --TESTING PURPOSES
END FIRST_ASSGN_DT
FROM MANAGER_HISTORY H
INNER JOIN CP CCP ON H.CLIID = CCP.CLIID
INNER JOIN CLIENT C ON CCP.CLIID = C.CLIID
INNER JOIN PROGRAM CP ON PROGRAMID = CP.PROGRAMID
LEFT JOIN LAST_VALUE_BEFORE_START_DT LVBS ON P.CL_ID = LVBS.CL_ID
LEFT JOIN MIN_VALUE_BETWEEN_PROGRAM MVBP ON P.CL_ID = MVBP.CL_ID
WHERE 1=1
AND CP.TYPEID IN (13,200,11001)
)X)Z
WHERE 1=1
AND Z.RNK = 1

SQL Server Delete Rows from Table leaving the record with the Max CreationDate

I want to delete the older records from the table based on creation date,leaving the latest one
attempted SQL,but did not work.
SELECT *
--DELETE L
FROM ItemPriceListMap L
LEFT JOIN (
SELECT ItemPriceListUID3,MAX(CAST(CreationDate as DATE)) MaxDate
FROM ItemPriceListMap
GROUP BY ItemPriceListUID3
)M ON L.ItemPriceListUID3 = M.ItemPriceListUID3 AND CAST(L.CreationDate as DATE) = M.MaxDate
WHERE M.ItemPriceListUID3 IS NULL
The view of the mapping
SELECT I.Description,ipl.UnitListPrice1,iplmp.VatMRP,iplmp.CreationDate FROM ItemPriceListMap iplmp
INNER JOIN ItemPriceList ipl ON iplmp.ItemPriceListUID3 = ipl.UID
INNER JOIN Item i ON ipl.ItemUID = i.UID
ORDER BY I.Description,iplmp.CreationDate
EDIT:
More Sample Data
Using this SQL
SELECT I.Description,iplmp.ItemPriceListUID3,iplmp.CreationDate FROM ItemPriceListMap iplmp
INNER JOIN ItemPriceList ipl ON iplmp.ItemPriceListUID3 = ipl.UID
INNER JOIN Item i ON ipl.ItemUID = i.UID
ORDER BY I.Description,iplmp.CreationDate
so after I execute the delete command the highlighted row should be left in the table(yellow),highlighted in blue is the same Item
TRY THIS: You can use your own query by doing some simple changes as below, you have to join as <> with the max date so it will not delete that record, only delete others which matches ItemPriceListUID3 and <> MaxDate
SELECT *
--DELETE L
FROM ItemPriceListMap L
INNER JOIN (SELECT MAX(CAST(CreationDate as DATE)) MaxDate
FROM ItemPriceListMap
) M ON CAST(L.CreationDate as DATE) <> M.MaxDate
Try this :
DELETE L
FROM ItemPriceListMap L
WHERE CreationDate <> (SELECT MAX(CreationDate) MaxDate
FROM ItemPriceListMap LL
WHERE L.ItemPriceListUID3 = LL.ItemPriceListUID3)
Note : Take backup of your data first.
Use a CTE and a row_number
with CTE as
(
select a1.*, row_number() over(
partition by ItemPriceListUID3 -- remove this if you don't need the grouping
order by CreationDate desc) as R_ORD
from ItemPriceListMap a1
)
delete
from CTE
where R_ORD > 1

Obtaining only first result from a LEFT JOIN

I'm trying to get the first result of a LEFT JOIN for each row of a SELECT statement.
Because now right now, if I have 100 rows in the joined table, I'll get 100 times the same row from the SELECT. I'd just need the first joined row so that way I wouldn't get any duplicates.
I can't use GROUP BY because I have to get more than only one row from the table.
Here's a basic version of my query:
SELECT bg.PatientID, DATEDIFF(hour, bg.CreateDate, GETDATE()) TimeToTarget
FROM BloodGlucose bg
LEFT JOIN IVProtocol i ON i.PatientID = bg.PatientID
WHERE bg.BGValue >= i.TargetLow AND bg.BGValue <= i.TargetHigh
ORDER BY bg.PatientID ASC
I tried using DISTINCT but since the data from bg.CreateDate isn't always the same it returns duplicates.
I just need the FIRST row of that left joined table.
Any ideas/suggestions?
Thanks!
;WITH x AS
(
SELECT
bg.PatientID,
TimeToTarget = DATEDIFF(hour, bg.CreateDate, GETDATE()),
rn = ROW_NUMBER() OVER (PARTITION BY bg.PatientID ORDER BY bg.CreatedDate DESC)
FROM dbo.BloodGlucose AS bg
LEFT JOIN dbo.IVProtocol AS i
ON i.PatientID = bg.PatientID
WHERE bg.BGValue >= i.TargetLow
AND bg.BGValue <= i.TargetHigh
)
SELECT PatientID, TimeToTarget
FROM x
WHERE rn = 1
ORDER BY PatientID;
To join to other results:
;WITH x AS
(
... same as above ...
)
SELECT x.PatientID, x.TimeToTarget, y.Something
FROM x INNER JOIN dbo.SomethingElse AS y
ON x.PatientID = y.PatientID
WHERE x.rn = 1
ORDER BY x.PatientID;
SELECT bg.PatientID, DATEDIFF(hour, bg.CreateDate, GETDATE()) TimeToTarget
FROM BloodGlucose bg
cross apply (
select top 1 *
from IVProtocol i
where i.PatientID = bg.PatientID
order by SOME_CRITERA
) i
WHERE bg.BGValue >= i.TargetLow AND bg.BGValue <= i.TargetHigh
ORDER BY bg.PatientID ASC
Cross apply is a handy tool for such situations. It works like a join but you can use variables inside the subquery.