UNPIVOT Data with over Fourty Columns - sql-server

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

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))

Microsoft sql select distinct certain columns

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

Alpha Numeric ID's Formatting

I am generating an alpha numeric ID using the first three characters of field LastName and then an incrementing 3 digit number. The query I am using in MSSQL 2012 is:
SELECT LastName, FirstName,
UPPER(LEFT(LastName, 3)) + LEFT('000', LEN(ROW_NUMBER()
OVER (PARTITION BY LEFT(LastName, 3)ORDER BY LEFT(LastName, 3)) )+1)
+ CAST(ROW_NUMBER() OVER (PARTITION BY
LEFT(LastName, 3)ORDER BY LEFT(LastName, 3)) AS NVARCHAR(1000)) AS ID
FROM #Table
The query works relatively well however once the numeric increments to two rather than it ending 010 it is 00010. The same would be true once the numeric portion increments to three digits. For example, I would like an output like follows:
╔══════════╦═══════════╦══════════╗
║ LastName ║ FirstName ║ ID ║
╠══════════╬═══════════╬══════════╣
║ Jones ║ David ║ JON001 ║
║ Jones ║ David ║ JON002 ║
║ Jones ║ David ║ JON003 ║
║ Jones ║ David ║ JON004 ║
║ Smith ║ John ║ SMI001 ║
║ Smith ║ John ║ SMI002 ║
║ Smith ║ Robert ║ SMI003 ║
║ Smith ║ John ║ SMI004 ║
║ Smith ║ John ║ SMI005 ║
║ Smith ║ Robert ║ SMI006 ║
║ Smith ║ John ║ SMI007 ║
║ Smith ║ John ║ SMI008 ║
║ Smith ║ Robert ║ SMI009 ║
║ Smith ║ John ║ SMI010 ║
║ Smith ║ John ║ SMI011 ║
║ Smith ║ Robert ║ SMI012 ║
║ .. ║ .. ║ .. ║
║ Smith ║ James ║ SMI100 ║
╚══════════╩═══════════╩══════════╝
I'm not sure how to address the incrementing numerical fields. Thanks for any help you can provide.
From the right instead of the left?
SELECT *, UPPER(LEFT(LastName, 3)) + RIGHT('000' + CAST(ID AS VARCHAR(3)), 3)
FROM (
SELECT
LastName,
FirstName,
ROW_NUMBER() OVER (PARTITION BY LEFT(LastName, 3) ORDER BY LastName) AS ID
FROM #table
) T

Resources