Microsoft sql select distinct certain columns - sql-server

I am changing mysql queries to microsoft sql server 2008 queries, and in order to apply limit I need to select a ROW_NUMBER() that accumlates over each row and then apply a where condition WHERE RowNum >= 0 AND RowNum < 0 + 20 to select a certain limit with offset.
My issue however is that I can no longer select distinct because I have a column RowNum that is different with each row, here's my query:
USE mydatabase
GO
WITH Results_CTE
AS (
SELECT DISTINCT C.firstname
,C.lastname
,C.id AS clientid
,QC.category_name
,QR.id
,QR.cid
,QR.catid
,QR.rhid
,ROW_NUMBER() OVER (
ORDER BY QR.id DESC
) AS RowNum
FROM cms_question_report QR
,cms_clients C
,cms_questioncategory QC
WHERE C.id = QR.cid
AND QR.catid = '3'
AND QR.catid = QC.id
)
SELECT *
FROM Results_CTE
WHERE RowNum >= 0
AND RowNum < 0 + 20
And the results are:
╔═══════════╦══════════╦══════════╦═══════════════╦═══════╦═════╦═══════╦══════╦════════╗
║ firstname ║ lastname ║ clientid ║ category_name ║ id ║ cid ║ catid ║ rhid ║ RowNum ║
╠═══════════╬══════════╬══════════╬═══════════════╬═══════╬═════╬═══════╬══════╬════════╣
║ test ║ testing ║ 121 ║ Activity Log ║ 81499 ║ 121 ║ 3 ║ 0 ║ 19 ║
║ test ║ testing ║ 121 ║ Activity Log ║ 81498 ║ 121 ║ 3 ║ 0 ║ 20 ║
║ test ║ testing ║ 121 ║ Activity Log ║ 81497 ║ 121 ║ 3 ║ 0 ║ 21 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81496 ║ 120 ║ 3 ║ 0 ║ 22 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81495 ║ 120 ║ 3 ║ 0 ║ 23 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81494 ║ 120 ║ 3 ║ 0 ║ 24 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81493 ║ 120 ║ 3 ║ 0 ║ 25 ║
╚═══════════╩══════════╩══════════╩═══════════════╩═══════╩═════╩═══════╩══════╩════════╝
I took an example from the middle of the result. What I'm after is for example:
╔═══════════╦══════════╦══════════╦═══════════════╦═══════╦═════╦═══════╦══════╦════════╗
║ firstname ║ lastname ║ clientid ║ category_name ║ id ║ cid ║ catid ║ rhid ║ RowNum ║
╠═══════════╬══════════╬══════════╬═══════════════╬═══════╬═════╬═══════╬══════╬════════╣
║ test ║ testing ║ 121 ║ Activity Log ║ 81497 ║ 121 ║ 3 ║ 0 ║ 21 ║
║ test ║ test ║ 120 ║ Activity Log ║ 81496 ║ 120 ║ 3 ║ 0 ║ 22 ║
╚═══════════╩══════════╩══════════╩═══════════════╩═══════╩═════╩═══════╩══════╩════════╝
Where I am trying to group the results by clientid. How do I achieve that?

USE ctarspla_mercycs
GO
WITH Results_CTE AS
(SELECT *, ROW_NUMBER() OVER (ORDER BY CLIENTID DESC) AS RowNum
FROM (SELECT DISTINCT
C.firstname,
C.lastname,
C.id as clientid,
QC.category_name,
QR.catid,
QR.rhid
FROM
cms_question_report QR,
cms_clients C,
cms_questioncategory QC
WHERE C.id=QR.cid
AND QR.catid=3
AND QR.catid=QC.id) t1)
SELECT * FROM Results_CTE
WHERE RowNum >= 0
AND RowNum < 0 + 20

Related

T-SQL: I'm trying to get the latest row of a column but also the sum of another column

I have the following table, it displays the SalesQty and the StockQty grouped by Article, Supplier, Branch and Month.
╔════════╦════════╦══════════╦═════════╦══════════╦══════════╗
║ Month ║ Branch ║ Supplier ║ Article ║ SalesQty ║ StockQty ║
╠════════╬════════╬══════════╬═════════╬══════════╬══════════╣
║ 201811 ║ 333 ║ 2 ║ 3122 ║ 4 ║ 11 ║
║ 201811 ║ 345 ║ 1 ║ 1234 ║ 2 ║ 10 ║
║ 201811 ║ 345 ║ 1 ║ 4321 ║ 3 ║ 11 ║
║ 201812 ║ 333 ║ 2 ║ 3122 ║ 2 ║ 4 ║
║ 201812 ║ 345 ║ 1 ║ 1234 ║ 3 ║ 12 ║
║ 201812 ║ 345 ║ 1 ║ 4321 ║ 4 ║ 5 ║
║ 201901 ║ 333 ║ 2 ║ 3122 ║ 1 ║ 8 ║
║ 201901 ║ 345 ║ 1 ║ 1234 ║ 6 ║ 9 ║
║ 201901 ║ 345 ║ 1 ║ 4321 ║ 2 ║ 8 ║
║ 201902 ║ 333 ║ 2 ║ 3122 ║ 7 ║ NULL ║
║ 201902 ║ 345 ║ 1 ║ 1234 ║ 4 ║ 13 ║
║ 201902 ║ 345 ║ 1 ║ 4321 ║ 1 ║ 10 ║
╚════════╩════════╩══════════╩═════════╩══════════╩══════════╝
Now I want to sum the SalesQty and get the latest StockQty and group them by Article, Supplier, Branch.
The final result should look like this:
╔════════╦══════════╦═════════╦═════════════╦════════════════╗
║ Branch ║ Supplier ║ Article ║ SumSalesQty ║ LatestStockQty ║
╠════════╬══════════╬═════════╬═════════════╬════════════════╣
║ 333 ║ 2 ║ 3122 ║ 14 ║ NULL ║
║ 345 ║ 1 ║ 1234 ║ 15 ║ 13 ║
║ 345 ║ 1 ║ 4321 ║ 10 ║ 10 ║
╚════════╩══════════╩═════════╩═════════════╩════════════════╝
I already tried this but it gives me an error, and i have no idea what i have to do in this case.
I've made this example so you can try it by yourself. db<>fiddle
SELECT
Branch,
Supplier,
Article,
SumSalesQty = SUM(SalesQty),
-- my attempt
LatestStockQty = (SELECT StockQty FROM TestTable i
WHERE MAX(Month) = Month
AND TT.Branch = i. Branch
AND TT.Supplier = i.Branch
AND TT.Article = i.Branch)
FROM
TestTable TT
GROUP BY
Branch, Supplier, Article
Thank you for your help!
We can try using ROW_NUMBER here, to isolate the latest record for each group:
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (PARTITION BY Branch, Supplier, Article
ORDER BY Month DESC) rn,
SUM(SalesQty) OVER (PARTITION BY Branch, Supplier, Article) SumSalesQty
FROM TestTable t
)
SELECT
Month,
Branch,
Supplier,
Article,
SumSalesQty,
StockQty
FROM cte
WHERE rn = 1;
Inside the CTE we compute, for each Branch/Supplier/Article group a row number value, starting with 1 for the most recent month. We also compute the sum of the sales quantity over the same partition. Then, we only need to select all rows from that CTE where the row number is equal to 1.
Demo
A similar approach but without the CTE
SELECT top 1 with ties
Branch
, Supplier
, Article
, SUM(SalesQty) OVER (PARTITION BY Branch, Supplier, Article) SumSalesQty
, tt.StockQty as LatestStockQty
FROM TestTable TT
order by ROW_NUMBER() OVER (PARTITION BY Branch, Supplier, Article ORDER BY Month DESC)

Group by Clause in two table - SQL Server

I have two tables with name of WH_table and Store_table,I am trying to create query to get result as mentioned below result table ,Can you anyone help to create query
Warehouse table
╔══════════════╦═════╗
║ Item ║ Qty ║
╠══════════════╬═════╣
║ Foot-ball ║ 1 ║
║ Foot-ball ║ 1 ║
║ Gloves ║ 1 ║
║ Track suites ║ 1 ║
╚══════════════╩═════╝
Store table
╔═══════════╦═════╗
║ Item ║ Qty ║
╠═══════════╬═════╣
║ Foot-ball ║ 1 ║
║ Foot-ball ║ 1 ║
║ Gloves ║ 1 ║
╚═══════════╩═════╝
Result
╔════════════╦═══════════╦══════════════╗
║ Item ║ Qty in WH ║ Qty in Store ║
╠════════════╬═══════════╬══════════════╣
║ Foot-ball ║ 2 ║ 2 ║
║ Gloves ║ 1 ║ 1 ║
║ Tracksuite ║ 1 ║ 0 ║
╚════════════╩═══════════╩══════════════╝
You can use a FULL JOIN:
SELECT ISNULL(w.Item,s.Item) Item,
ISNULL(w.Qty,0) Qty_In_WH,
ISNULL(s.Qty,0) Qty_In_Store
FROM ( SELECT Item,
SUM(Qty) Qty
FROM dbo.Warehouse
GROUP BY Item) w
FULL JOIN ( SELECT Item,
SUM(Qty) Qty
FROM dbo.Store
GROUP BY Item) s
ON w.Item = s.Item;

SQL Query Group by issue

I have a table with records like history table.
I have created following Query to get the desired result. However, it is not giving me final result that I want.
DECLARE #Customer_Id BIGINT=4
DECLARE #Month INT=2
SELECT
FH.UniqueFileId,FH.DocumentNo,MIN(FH.DateStamp) AS ReceivedTime,MAX(FH.DateStamp) SentTime
FROM
[dbo].[FileMovement_History] FH
INNER JOIN [dbo].[User_Master] UM ON UM.User_Id=FH.User_Id
WHERE
FH.UniqueFileId Is Not NULL AND FH.UniqueFileId!=''
AND (#Customer_Id IS NULL OR UM.Customer_id = #Customer_Id)
AND MONTH(FH.DateStamp)=#Month
GROUP BY
FH.UniqueFileId,FH.DocumentNo
Order BY
FH.UniqueFileId
╔════════════════╦══════════════════════╦═════════════════════════════╦═════════════════════════════╗
║ UniqueFileId ║ DocumentNo ║ ReceivedTime ║ SentTime ║
╠════════════════╬══════════════════════╬═════════════════════════════╬═════════════════════════════╣
║ HS5536387_10HE ║ NULL ║ 2017-02-02 13:13:37.3451906 ║ 2017-02-02 13:19:19.0114047 ║
║ HS5536387_10HE ║ 120097583 / MC / CL7 ║ 2017-02-02 13:19:18.9801503 ║ 2017-02-02 13:19:19.1051605 ║
║ HS5536387_1HE ║ NULL ║ 2017-02-02 13:13:34.6887572 ║ 2017-02-02 13:21:37.7405652 ║
║ HS5536387_1HE ║ 3701341 ║ 2017-02-02 13:21:37.6936641 ║ 2017-02-02 13:21:37.8499434 ║
║ HS5536387_3HE ║ NULL ║ 2017-02-02 13:13:35.5950873 ║ 2017-02-02 13:19:19.9958519 ║
╚════════════════╩══════════════════════╩═════════════════════════════╩═════════════════════════════╝
I want the following result where I need one entry for one UniqueFileId with minimum of datestamp and maximum of datestamp. I want extra column where is shows total timeduration between minimum and maximum date.
╔════════════════╦══════════════════════╦═════════════════════════════╦═════════════════════════════╗
║ UniqueFileId ║ DocumentNo ║ ReceivedTime ║ SentTime ║
╠════════════════╬══════════════════════╬═════════════════════════════╬═════════════════════════════╣
║ HS5536387_10HE ║ 120097583 / MC / CL7 ║ 2017-02-02 13:13:37.3451906 ║ 2017-02-02 13:19:19.0114047 ║
║ HS5536387_1HE ║ 3701341 ║ 2017-02-02 13:13:34.6887572 ║ 2017-02-02 13:21:37.7405652 ║
║ HS5536387_3HE ║ NULL ║ 2017-02-02 13:13:35.5950873 ║ 2017-02-02 13:19:19.9958519 ║
╚════════════════╩══════════════════════╩═════════════════════════════╩═════════════════════════════╝
Do a grouping only by the UniqueFileId field, and instead take the MIN(DocumentNo) value of this column:
SELECT FH.UniqueFileId,
MIN(FH.DocumentNo) AS DocumentNo,
MIN(FH.DateStamp) AS ReceivedTime,
MAX(FH.DateStamp) AS SentTime
FROM [dbo].[FileMovement_History] FH
INNER JOIN [dbo].[User_Master] UM
ON UM.User_Id = FH.User_Id
WHERE COALESCE(FH.UniqueFileId, '') <> '' AND
(#Customer_Id IS NULL OR UM.Customer_id = #Customer_Id) AND
MONTH(FH.DateStamp) = #Month
GROUP BY FH.UniqueFileId
ORDER BY FH.UniqueFileId
If you want to show the difference in time between the sent and received time in the format hh:mm:ss, then you can use the following expression:
CAST(DATEDIFF(HOUR, MIN(FH.DocumentNo), MAX(FH.DocumentNo)) AS NVARCHAR(200)) + ":" +
CAST(DATEDIFF(MINUTE, MIN(FH.DocumentNo), MAX(FH.DocumentNo)) % 60 AS NVARCHAR(200)) +":" +
CAST(DATEDIFF(SECOND, MIN(FH.DocumentNo), MAX(FH.DocumentNo)) % 60 AS NVARCHAR(200))

UNPIVOT Data with over Fourty Columns

Test Data
DECLARE #T table
( ClientID INT, Dated DateTime,Value1 varchar(10),Value2 varchar(10),
Value3 varchar(10),Value4 varchar(10),Value5 varchar(10),Value6 varchar(10)
,Value7 varchar(10),Value8 varchar(10),Value9 varchar(10)
)
INSERT INTO #T values
(1,'2014-01-06 16:27:47.440','High','Low','Medium','High','Medium','Low','Medium','High','Low'),
(2,'2014-01-06 16:27:47.440','Medium','High','Low','Medium','High','Low','Medium','Low','Medium'),
(1,'2014-01-01 16:27:47.440','Medium','Low','High','Medium','Low','Medium','High','Low','Medium')
SELECT * FROM #T
╔══════════╦═════════════════════════╦════════╦════════╦════════╦════════╦════════╦════════╦════════╦════════╦════════╗
║ ClientID ║ Dated ║ Value1 ║ Value2 ║ Value3 ║ Value4 ║ Value5 ║ Value6 ║ Value7 ║ Value8 ║ Value9 ║
╠══════════╬═════════════════════════╬════════╬════════╬════════╬════════╬════════╬════════╬════════╬════════╬════════╣
║ 1 ║ 2014-06-01 16:27:47.440 ║ High ║ Low ║ Medium ║ High ║ Medium ║ Low ║ Medium ║ High ║ Low ║
║ 2 ║ 2014-06-01 16:27:47.440 ║ Medium ║ High ║ Low ║ Medium ║ High ║ Low ║ Medium ║ Low ║ Medium ║
║ 1 ║ 2014-01-01 16:27:47.440 ║ Medium ║ Low ║ High ║ Medium ║ Low ║ Medium ║ High ║ Low ║ Medium ║
╚══════════╩═════════════════════════╩════════╩════════╩════════╩════════╩════════╩════════╩════════╩════════╩════════╝
My Query
SELECT TOP 1
B.Value1 AS Historical_Value1, A.Value1 AS Recent_Value1
, B.Value2 AS Historical_Value2, A.Value2 AS Recent_Value2
, B.Value3 AS Historical_Value3, A.Value3 AS Recent_Value3
, B.Value4 AS Historical_Value4, A.Value4 AS Recent_Value4
, B.Value5 AS Historical_Value5, A.Value5 AS Recent_Value5
, B.Value6 AS Historical_Value6, A.Value6 AS Recent_Value6
, B.Value7 AS Historical_Value7, A.Value7 AS Recent_Value7
, B.Value8 AS Historical_Value8, A.Value8 AS Recent_Value8
, B.Value9 AS Historical_Value9, A.Value9 AS Recent_Value9
FROM #T A INNER JOIN #T B
ON A.ClientID = B.ClientID
WHERE B.Dated < A.Dated
ORDER BY A.Dated DESC, B.Dated DESC
As you can see I am pulling out The lastest Recordings for all the values and the recording recorded prior to that. Recent Values and Historical Values respectively.
Which returns me Data back in the following format.
Current OUTPUT
╔═══════════════════╦═══════════════╦═══════════════════╦═══════════════╦═══════════════════╦═══════════════╦═══════════════════╦═══════════════╦═══════════════════╦═══════════════╦═══════════════════╦═══════════════╦═══════════════════╦═══════════════╦═══════════════════╦═══════════════╦═══════════════════╦═══════════════╗
║ Historical_Value1 ║ Recent_Value1 ║ Historical_Value2 ║ Recent_Value2 ║ Historical_Value3 ║ Recent_Value3 ║ Historical_Value4 ║ Recent_Value4 ║ Historical_Value5 ║ Recent_Value5 ║ Historical_Value6 ║ Recent_Value6 ║ Historical_Value7 ║ Recent_Value7 ║ Historical_Value8 ║ Recent_Value8 ║ Historical_Value9 ║ Recent_Value9 ║
╠═══════════════════╬═══════════════╬═══════════════════╬═══════════════╬═══════════════════╬═══════════════╬═══════════════════╬═══════════════╬═══════════════════╬═══════════════╬═══════════════════╬═══════════════╬═══════════════════╬═══════════════╬═══════════════════╬═══════════════╬═══════════════════╬═══════════════╣
║ Medium ║ High ║ Low ║ Low ║ High ║ Medium ║ Medium ║ High ║ Low ║ Medium ║ Medium ║ Low ║ High ║ Medium ║ Low ║ High ║ Medium ║ Low ║
╚═══════════════════╩═══════════════╩═══════════════════╩═══════════════╩═══════════════════╩═══════════════╩═══════════════════╩═══════════════╩═══════════════════╩═══════════════╩═══════════════════╩═══════════════╩═══════════════════╩═══════════════╩═══════════════════╩═══════════════╩═══════════════════╩═══════════════╝
Desired OUTPUT
But I would like to UNPIVOT the data so it is shown as Follows, I have seen a lot of question on SO but none of them seems to fit my requirement. Any pointer any advice is most welcome thank you.
╔════════╦════════════╦════════╗
║ Values ║ Historical ║ Recent ║
╠════════╬════════════╬════════╣
║ Value1 ║ High ║ Medium ║
║ Value2 ║ Low ║ Low ║
║ Value3 ║ Medium ║ High ║
║ Value4 ║ High ║ Medium ║
║ Value5 ║ High ║ Medium ║
╚════════╩════════════╩════════╝
This would be one way to do it:
;WITH up AS
(
SELECT * FROM #T
UNPIVOT
(
val FOR n IN (Value1,value2,value3,value4,value5,value6,value7,value8,value9)
) as pv
)
SELECT
A.ClientID,
A.Dated,
A.n as Values,
A.val as Recent,
B.val as History
FROM
up as A
JOIN up as B
ON A.ClientID = B.ClientID
AND A.n = B.n
WHERE B.Dated < A.Dated
ORDER BY
A.Dated DESC, B.Dated DESC

Unique ID for each row in recursive CTE hierarchy with multiple nodes

I have a table containing a set of links that form a hierarchy. The big problem is that each link may be used several times (in different positions). I need to be able to distinguish between each "instance" of each node.
For example in the following data, link "D-G" will show up several times:
╔════════════╦════════╗
║ SOURCE ║ TARGET ║
╠════════════╬════════╣
║ A ║ B ║
║ A ║ C ║
║ B ║ D ║
║ B ║ E ║
║ B ║ F ║
║ C ║ D ║
║ C ║ E ║
║ C ║ F ║
║ D ║ G ║
║ E ║ D ║
║ F ║ D ║
╚════════════╩════════╝
I can build the hierarchy using a recursive CTE without any problems, but I want to give each row in the results a unique ID and link it to the parent node's unique ID.
My original idea was to assign a unique ID to each row using Row_Number() + Max(ID) up to this point and have the row inherit it's parents ID, but further reading and trial & error showed that this wont work :-(
Does anybody have an idea how to solve this problem (or at least give me a clue)?
The results should be something like this:
╔═════════════╦═════════════╦═══════════╦═══════════╗
║ SOURCE_DESC ║ TARGET_DESC ║ Source_ID ║ Target_ID ║
╠═════════════╬═════════════╬═══════════╬═══════════╣
║ A ║ B ║ 0 ║ 1 ║
║ A ║ C ║ 0 ║ 2 ║
║ B ║ D ║ 1 ║ 6 ║
║ B ║ E ║ 1 ║ 7 ║
║ B ║ F ║ 1 ║ 8 ║
║ C ║ D ║ 2 ║ 3 ║
║ C ║ E ║ 2 ║ 4 ║
║ C ║ F ║ 2 ║ 5 ║
║ D ║ G ║ 3 ║ 13 ║
║ E ║ D ║ 4 ║ 11 ║
║ F ║ D ║ 5 ║ 10 ║
║ D ║ G ║ 6 ║ 14 ║
║ E ║ D ║ 7 ║ 12 ║
║ F ║ D ║ 8 ║ 9 ║
║ D ║ G ║ 9 ║ 18 ║
║ D ║ G ║ 10 ║ 17 ║
║ D ║ G ║ 11 ║ 16 ║
║ D ║ G ║ 12 ║ 15 ║
╚═════════════╩═════════════╩═══════════╩═══════════╝
Here the "D-G" link shows up several times, but in each instance it has a different ID and a different parent ID!
I've managed to do it but I'm not happy with the way I did it. It doesn't seems very efficient (not important for this example but very important for much larger sets!)
WITH JUNK_DATA
AS (SELECT *,
ROW_NUMBER()
OVER (
ORDER BY SOURCE) RN
FROM LINKS),
RECUR
AS (SELECT T1.SOURCE,
T1.TARGET,
CAST('ROOT' AS VARCHAR(MAX)) NAME,
1 AS RAMA,
CAST(T1.RN AS VARCHAR(MAX)) + ',' AS FULL_RAMA
FROM JUNK_DATA T1
LEFT JOIN JUNK_DATA T2
ON T1.SOURCE = T2.TARGET
WHERE T2.TARGET IS NULL
UNION ALL
SELECT JUNK_DATA.SOURCE,
JUNK_DATA.TARGET,
CASE
WHEN RAMA = 1 THEN (SELECT [DESC]
FROM NAMES
WHERE ID = JUNK_DATA.SOURCE)
ELSE NAME
END NAME,
RAMA + 1 AS RAMA,
FULL_RAMA
+ CAST(JUNK_DATA.RN AS VARCHAR(MAX)) + ','
FROM (SELECT *
FROM JUNK_DATA)JUNK_DATA
INNER JOIN (SELECT *
FROM RECUR) RECUR
ON JUNK_DATA.SOURCE = RECUR.TARGET),
FINAL_DATA
AS (SELECT T2.[DESC] SOURCE_DESC,
T3.[DESC] TARGET_DESC,
RECUR.*,
ROW_NUMBER()
OVER (
ORDER BY RAMA) ID
FROM RECUR
INNER JOIN NAMES T2
ON RECUR.SOURCE = T2.ID
INNER JOIN NAMES T3
ON RECUR.TARGET = T3.ID)
SELECT T1.SOURCE_DESC,
T1.TARGET_DESC,
ISNULL(T2.ID, 0) AS SOURCE_ID,
T1.ID TARGET_ID
FROM FINAL_DATA T1
LEFT JOIN (SELECT ID,
FULL_RAMA
FROM FINAL_DATA)T2
ON LEFT(T1.FULL_RAMA, LEN(T1.FULL_RAMA) - CHARINDEX(',',
REVERSE(T1.FULL_RAMA), 2))
+ ',' = T2.FULL_RAMA
ORDER BY SOURCE_ID,
TARGET_ID
Check it out on SQL fiddle.

Resources