I have the following database table:
| Article | Material |
|------------|-------------|
| article001 | material001 |
| article001 | material002 |
| article002 | material002 |
| article002 | material003 |
| article002 | material004 |
| article003 | material002 |
| article004 | material003 |
| article004 | material004 |
| article004 | material005 |
| article004 | material006 |
I want to achive a result like this:
| Article | Material1 | Material2 | Material3 | Material4 |
|------------|-------------|-------------|-------------|-------------|
| article001 | material001 | material002 | | |
| article002 | material002 | material003 | material004 | |
| article003 | material002 | | | |
| article004 | material003 | material004 | material005 | material006 |
I have already tried various possibilities (Pivot, CTE, Temp Tables). Unfortunately I do not get it. I'm pretty new to SQL.
A simple solution is a conditional aggregation (if you have a max number of materials). Let me know if you need to dynamic.
Select Article
,Material1 = max(case when RN=1 then Material else '' end)
,Material2 = max(case when RN=2 then Material else '' end)
,Material3 = max(case when RN=3 then Material else '' end)
,Material4 = max(case when RN=4 then Material else '' end)
From (
Select *
,RN = Row_Number() over (Partition By Article Order by Material)
From YourTable
) A
Group By Article
Returns
EDIT - Dynamic Pivot
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName('Material'+cast(RN as varchar(25))) From (Select Distinct RN = Row_Number() over (Partition By Article Order by Material) From Yourtable) A Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select [Article],' + #SQL + '
From (
Select Article,Material
,Item = ''Material''+cast(Row_Number() over (Partition By Article Order by Material) as varchar(25))
From YourTable
) A
Pivot (max(Material) For [Item] in (' + #SQL + ') ) p'
Exec(#SQL);
Related
My Input Table is
+--------+----------+----------+-------+
| userid | teamname | task1 | task2 |
+--------+----------+----------+-------+
| 101 | T1 | 101task1 | desc1 |
| 101 | T1 | 101task2 | desc2 |
| 101 | T2 | 101task1 | desc3 |
| 101 | T2 | 101task2 | desc4 |
| 101 | T2 | 101task2 | desc5 |
| 102 | T3 | 102task1 | desc6 |
| 102 | T3 | 102task2 | desc7 |
| 102 | T3 | 102task3 | desc8 |
| 102 | T3 | 102task4 | desc9 |
+--------+----------+----------+-------+
I want the output as follow, to pivot(dynamic) task1+task2
+--------+----------+----------------+----------------+----------------+----------------+
| userid | teamname | 1 | 2 | 3 | 4 |
+--------+----------+----------------+----------------+----------------+----------------+
| 101 | T1 | 101task1 desc1 | 101task2 desc2 | | |
| 101 | T2 | 101task1 desc3 | 101task2 desc4 | 101task2 desc5 | |
| 102 | T3 | 102task1 desc6 | 102task2 desc7 | 102task3 desc8 | 102task4 desc9 |
+--------+----------+----------------+----------------+----------------+----------------+
I tried to pivot task1 and it worked like sample code SampleCode,
but when I pivot max(task1+task2) I get error
You need to combine them in source of pivot table and use them by giving them an alias.
set #query = 'SELECT userid,teamname,' + #cols + ' from
(
select userid,
teamname,
concat(task1,task2) as col, --Combine here
ROW_NUMBER() OVER(PARTITION BY userid,teamname order by task1 asc) AS Row#
from #yt
) x
pivot
(
max(col) --Alias used here
for row# in (' + #cols + ')
) p '
execute(#query);
Edit : To add a space in between fields
set #query = 'SELECT userid,teamname,' + #cols + ' from
(
select userid,
teamname,
CONCAT(task1,SPACE(1),task2) col,
ROW_NUMBER()OVER(PARTITION BY userid,teamname order by task1 asc) AS Row#
from #yt
) x
pivot
(
max(col)
for row# in (' + #cols + ')
) p '
execute(#query);
Compare historical rows (LAG rows based on ResultChngDt) and combine changed column values to single column. Looking for help in writing elegant/efficient SQL Server 2016 TSQL Code(without cursors).
I have a table with the structure and data like this:
+----+-------+--------------+---------------+--------+--------+--------------+
| ID | RepID | CollctedDate | CompletedDate | Result | Tcode | ResultChngDt |
+----+-------+--------------+---------------+--------+--------+--------------+
| 1 | 101 | 11/20/2017 | 12/13/2017 | | L-2190 | 12/13/2017 |
| 1 | 101 | 11/22/2017 | 12/15/2017 | POS | L-Afb | 1/5/2018 |
| 1 | 102 | 11/22/2017 | 12/15/2017 | | L-2191 | 12/15/2017 |
| 1 | 102 | 11/22/2017 | 12/15/2017 | POS | L-2192 | 12/31/2017 |
+----+-------+--------------+---------------+--------+--------+--------------+
I need to generate a report/result as follows:
+----+-------+---------------------------+--------------------------+--+
| ID | RepID | Previous | Current | |
+----+-------+---------------------------+--------------------------+--+
| 1 | 101 | CollctedDate:11/20/2017 | CollctedDate:11/22/2017 | |
| | | CompletedDate:12/13/2017 | CompletedDate:12/15/2017 | |
| | | Result: | Result:POS | |
| | | Tcode:L-2190 | Tcode:L-Afb | |
| 1 | 102 | CollctedDate:11/22/2017 | CollctedDate:11/22/2017 | |
| | | CompletedDate:12/15/2017 | CompletedDate:12/15/2017 | |
| | | Result: | Result:POS | |
| | | Tcode:L-2191 | Tcode:L-2192 | |
+----+-------+---------------------------+--------------------------+--+
CREATE TABLE [dbo].[Table1]
(
[ID] INT NULL,
[RepID] INT NULL,
[CollctedDate] DATETIME NULL,
[CompletedDate] DATETIME NULL,
[Result] VARCHAR(3) NULL,
[Tcode] VARCHAR(10) NULL,
[ResultChngDt] DATETIME NULL
) ON [PRIMARY];
GO
INSERT INTO [dbo].[Table1] ([ID], [RepID], [CollctedDate], [CompletedDate], [Result], [Tcode], [ResultChngDt])
VALUES (1, 101, N'11/20/2017', N'12/13/2017', N'', N'L-2190', N'12/13/2017')
, (1, 101, N'11/22/2017', N'12/15/2017', N'POS', N'L-Afb', N'1/5/2018')
, (1, 102, N'11/22/2017', N'12/15/2017', N'', N'L-2191', N'12/15/2017')
, (1, 102, N'11/22/2017', N'12/15/2017', N'POS', N'L-2192', N'12/31/2017')
Here's my query for your question:
WITH cte_LEADLAG AS(
SELECT ID,
RepID,
CollctedDate,
CompletedDate,
Result,
Tcode,
ResultChngDt,
CONCAT('CollectedDate:',CAST(CollctedDate AS DATETIME2), ' CompletedDate:', CAST(CompletedDate AS DATETIME2), ' Result:', Result, ' Tcode', Tcode) AS dates,
LAG(CollctedDate) OVER(PARTITION BY RepID ORDER BY CollctedDate) AS 'LAGCollectedDate' ,
lead(CollctedDate) OVER(PARTITION BY RepID ORDER BY CollctedDate) AS 'LEADCollectedDate',
LAG(CompletedDate) OVER(PARTITION BY RepID ORDER BY CompletedDate) AS 'LAGCompDate' ,
lead(CompletedDate) OVER(PARTITION BY RepID ORDER BY CompletedDate) AS 'LEADcompDate' ,
LEAD(Result) OVER(PARTITION BY RepID ORDER BY CompletedDate) AS 'LEADResult' ,
LEAD(Tcode) OVER(PARTITION BY RepID ORDER BY CompletedDate) AS 'LEADTcode'
FROM #temp
),
cte_FINAL AS(
SELECT distinct ID,
RepID,
CASE WHEN cte.LAGCollectedDate IS NULL THEN CONCAT('CollectedDate:',CAST(CollctedDate AS DATETIME2), ' CompletedDate:', CAST(CompletedDate AS DATETIME2), ' Result:', Result, ' Tcode', Tcode) end AS 'Previous',
CASE WHEN cte.LEADCollectedDate IS not NULL THEN CONCAT('CollectedDate:',CAST(cte.LEADCollectedDate AS DATETIME2), ' CompletedDate:', CAST(LEADcompDate AS DATETIME2), ' Result:', cte.LEADResult, ' Tcode', cte.LEADTcode) end AS 'Current'
FROM cte_LEADLAG AS cte
WHERE cte.LEADCollectedDate IN (SELECT MAX(LEADCollectedDate) FROM cte_LEADLAG WHERE cte_LEADLAG.RepID = cte.RepID))
)
SELECT *
FROM cte_FINAL;
Result:
with data as (
select *, row_number() over (partition by RepID order by ResultChgDt desc) as rn
from dbo.Table1
)
select
from data as d1 left outer join data as d2 on d2.rn = d1.rn + 1
where d1.rn = 1 -- I suppose you only want the two most recent??
This gives you all the data you need in a single row. You can handle report formatting to suit whatever requirements you have in whatever tool you're using for that.
This question already has answers here:
Convert Rows to columns using 'Pivot' in SQL Server
(9 answers)
Closed 6 years ago.
I have a table like below:
+-----------+------------+--------+
| Col1 | Col2 | Col3 |
+-----------+------------+--------+
| 12345678 | FirstName | John |
| 12345678 | LastName | Smith |
| 987456321 | LastName | Clancy |
| 987456321 | MiddleName | T |
| 987456321 | Height | 176cm |
| 654125878 | FirstName | Tan |
| 654125878 | Weight | 150lb |
+-----------+------------+--------+
How to convert that to:
+-----------+-----------+------------+----------+--------+--------+
| ID | FirstName | MiddleName | LastName | Height | Weight |
+-----------+-----------+------------+----------+--------+--------+
| 12345678 | John | null | Smith | null | null |
| 987456321 | null | T | Clancy | 176cm | null |
| 654125878 | Tan | null | null | null | 150lb |
+-----------+-----------+------------+----------+--------+--------+
I think a conditional aggregation would do the trick here.
Assuming you don't need dynamic
Select ID = Col1
,FirstName = max(case when Col2='FirstName' then Col3 else null end)
,MiddleName = max(case when Col2='MiddleName ' then Col3 else null end)
,LastName = max(case when Col2='LastName ' then Col3 else null end)
,Height = max(case when Col2='Height' then Col3 else null end)
,Weight = max(case when Col2='Weight' then Col3 else null end)
From YourTable
Group By Col1
If you need dynamic
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName([Col2]) From Yourtable Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select [Col1] as ID ,' + #SQL + '
From YourTable
Pivot (max(Col3) For [Col2] in (' + #SQL + ') ) p'
Exec(#SQL);
If it helps, the generated SQL for the dynamic Pivot is as follows:
Select [Col1] as ID ,[FirstName],[Height],[LastName],[MiddleName],[Weight]
From YourTable
Pivot (max(Col3) For [Col2] in ([FirstName],[Height],[LastName],[MiddleName],[Weight]) ) p
table:
+-----------+--------------+------------+------------+
| RequestID | RequestStaus | StartDate | EndDate |
+-----------+--------------+------------+------------+
| 1 | pending | 9/1/2015 | 10/2/2015 |
| 1 | in progress | 10/2/2015 | 10/20/2015 |
| 1 | completed | 10/20/2015 | 11/3/2015 |
| 1 | reopened | 11/3/2015 | null |
| 2 | pending | 9/5/2015 | 9/7/2015 |
| 2 | in progress | 9/7/2015 | 9/25/2015 |
| 2 | completed | 9/25/2015 | 10/7/2015 |
| 2 | reopened | 10/10/2015 | 10/16/2015 |
| 2 | completed | 10/16/2015 | null |
+-----------+--------------+------------+------------+
I would like to calculate the days opened but exclude the days between completed and reopened. For example, RequestID 1, the days opened will be (11/3/2015 - 9/1/2015) + (GetDate() - 11/3/2015), for request 2, the total days will be (10/7/2015 - 9/5/2015) + ( 10/16/2015 - 10/10/2015).
The result I want will be something like:
+-----------+-------------------------------+
| RequestID | DaysOpened |
+-----------+-------------------------------+
| 1 | 63 + (getdate() - 11/3/2015) |
| 2 | 38 |
+-----------+-------------------------------+
How do I approach this problem? thank you!
Tested. Works well. :)
Note:
1) I suppose the required result = (FirstCompleteEndDate - PendingStartDate)+(Sum of all the Reopen duration)
2) So I used the self joins. Table b provides the exact completed record which immediately follows the in process record for each RequestID. Table c provides Sum of all the Reopen duration.
--create tbl structure
create table #test (RequestID int, RequestStatus varchar(20), StartDate date, EndDate date)
go
--insert sample data
insert #test
select 1,'pending','09/01/2015','10/2/2015'
union all
select 1,'in progress','10/2/2015','10/20/2015'
union all
select 1,'completed','10/20/2015','11/3/2015'
union all
select 1,'reopened','11/3/2015',null
union all
select 2,'pending','09/05/2015','9/7/2015'
union all
select 2,'in progress','09/07/2015','9/25/2015'
union all
select 2,'completed','9/25/2015','10/7/2015'
union all
select 2,'reopened','10/10/2015','10/16/2015'
union all
select 2, 'completed','10/16/2015','11/12/2015'
union all
select 2,'reopened','11/20/2015',null
select * from #test
--below is solution
select a.RequestID, a.Startdate as [PendingStartDate], b.enddate as [FirstCompleteEndDate], c.startdate as [LatestReopenStartDate],
datediff(day,a.startdate,b.enddate)+c.ReopenDays as [days] from #test a
join (
select *, row_number()over(partition by RequestID,RequestStatus order by StartDate) as rid from #test
) as b
on a.RequestID = b.RequestID
join (
select distinct RequestID, RequestStatus, max(StartDate)over(partition by RequestID,RequestStatus) as StartDate,
Sum(Case when enddate is null then datediff(day,startdate,getdate())
when enddate is not null then datediff(day,startdate,enddate)
end)over(partition by RequestID,RequestStatus) as [ReopenDays]
from #test
where RequestStatus = 'reopened'
) as c
on b.RequestID = c.RequestID
where a.RequestStatus ='pending' and b.RequestStatus = 'completed' and b.rid = 1
Result:
I want to transpose my table.
I have simple 'Person' table as shown below.
+---+----------+------------+------------+----------------------+
|ID | Person | BirthDate | Phone | Email |
+---+----------+------------+------------+----------------------+
| 1 | Tom | 1985-11-08 | 1111111111 | tom#somedomain.com |
+---+----------+------------+------------+----------------------+
| 2 | Dick | 1982-02-24 | 2222222222 | dick#otherdomain.com |
+---+----------+------------+------------+----------------------+
| 3 | Harry | 1986-04-17 | 3333333333 | harry#thatdomain.com |
+---+----------+------------+------------+----------------------+
And I want this table to be transposed like below.
+-----------+--------------------+----------------------+----------------------+
| Key | Value1 | Value2 | Value3 |
+-----------+--------------------+----------------------+----------------------+
| ID | 1 | 2 | 3 |
+-----------+--------------------+----------------------+----------------------+
| Person | Tom | Dick | Harry |
+-----------+--------------------+----------------------+----------------------+
| BirthDate | 1985-11-08 | 1982-02-24 | 1986-04-17 |
+-----------+--------------------+----------------------+----------------------+
| Phone | 1111111111 | 2222222222 | 3333333333 |
+-----------+--------------------+----------------------+----------------------+
| Email | tom#somedomain.com | dick#otherdomain.com | harry#thatdomain.com |
+-----------+--------------------+----------------------+----------------------+
I am using MS SQL server 2008 R2.
Try this.. First u need to unpivot the columns using Cross apply to get the data in single row. Then pivot that row to get the result.
CREATE TABLE #tt
(ID INT,Person VARCHAR(50),BirthDate DATE,
Phone BIGINT,Email VARCHAR(50)
)
INSERT INTO #tt
VALUES (1,'Tom','1985-11-08',1111111111,'tom#somedomain.com' ),
( 2,'Dick','1982-02-24',2222222222,'dick#otherdomain.com'),
( 3,'Harry ','1986-04-17',3333333333,'harry#thatdomain.com' )
SELECT [key],
Max([value1]) [value1],
Max([value2]) [value2],
Max([value3]) [value3]
FROM (SELECT 'value' + CONVERT(VARCHAR(30), id) valued,
*
FROM #tt
CROSS apply (VALUES ('ID',
CONVERT(VARCHAR(50), ID)),
('Person',Person),
('BirthDate',CONVERT(VARCHAR(50), BirthDate)),
('Phone',CONVERT(VARCHAR(50), Phone)),
('Email',Email)) cp ([key], data))a
PIVOT (Max(data)
FOR valued IN([value1],[value2],[value3])) piv
GROUP BY [key]
DYNAMIC VERSION
Declare #cols varchar(max)='',#aggcols varchar(max)='',#sql nvarchar(max)
SELECT #cols+= ',value' + CONVERT(VARCHAR(30), id)
FROM #tt
SELECT #aggcols+= ',max([value' + CONVERT(VARCHAR(30), id) +']) value' + CONVERT(VARCHAR(30), id)
FROM #tt
select #cols= right(#cols,LEN(#cols)-1)
select #aggcols =right(#aggcols,LEN(#aggcols)-1)
set #sql = 'SELECT [key],
'+#aggcols+'
FROM (SELECT ''value'' + CONVERT(VARCHAR(30), id) valued,
*
FROM #tt
CROSS apply (VALUES (''ID'',CONVERT(VARCHAR(50), ID)),
(''Person'',Person),
(''BirthDate'',CONVERT(VARCHAR(50), BirthDate)),
(''Phone'',CONVERT(VARCHAR(50), Phone)),
(''Email'',Email)) cp ([key], data))a
PIVOT (Max(data)
FOR valued IN('+#cols+')) piv
GROUP BY [key] '
execute sp_executesql #sql
OUTPUT
+----------+--------------------+---------------------+----------------------+
|key | value1 | value2 | value3 |
+----------+--------------------+---------------------+----------------------+
|BirthDate | 1985-11-08 | 1982-02-24 | 1986-04-17 |
+----------+--------------------+---------------------+----------------------+
|Email | tom#somedomain.com |dick#otherdomain.com | harry#thatdomain.com |
+----------+--------------------+---------------------+----------------------+
|ID | 1 | 2 | 3 |
+----------+--------------------+---------------------+----------------------+
|Person | Tom | Dick | Harry |
+----------+--------------------+---------------------+----------------------+
|Phone | 1111111111 | 2222222222 | 3333333333 |
+----------+--------------------+---------------------+----------------------+