I have a scenario where I need to convert columns of table to rows
eg -
table - stocks:
ScripName ScripCode Price
-----------------------------------------
20 MICRONS 533022 39
I need to represent the table in the following format, but I just need this kind of representation for single row
ColName ColValue
-----------------------------
ScripName 20 MICRONS
ScripCode 533022
Price 39
so that I can directly bind the data to the datalist control.
Sound like you want to UNPIVOT
Sample from books online:
--Create the table and insert values as portrayed in the previous example.
CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
Emp3 int, Emp4 int, Emp5 int);
GO
INSERT INTO pvt VALUES (1,4,3,5,4,4);
INSERT INTO pvt VALUES (2,4,1,5,5,5);
INSERT INTO pvt VALUES (3,4,3,5,4,4);
INSERT INTO pvt VALUES (4,4,2,5,5,4);
INSERT INTO pvt VALUES (5,5,1,5,5,5);
GO
--Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt;
GO
Returns:
VendorID Employee Orders
---------- ---------- ------
1 Emp1 4
1 Emp2 3
1 Emp3 5
1 Emp4 4
1 Emp5 4
2 Emp1 4
2 Emp2 1
2 Emp3 5
2 Emp4 5
2 Emp5 5
see also: Unpivot SQL thingie and the unpivot tag
declare #T table (ScripName varchar(50), ScripCode varchar(50), Price int)
insert into #T values ('20 MICRONS', '533022', 39)
select
'ScripName' as ColName,
ScripName as ColValue
from #T
union all
select
'ScripCode' as ColName,
ScripCode as ColValue
from #T
union all
select
'Price' as ColName,
cast(Price as varchar(50)) as ColValue
from #T
select 'ScriptName', scriptName from table
union all
select 'ScriptCode', scriptCode from table
union all
select 'Price', price from table
As an alternative:
Using CROSS APPLY and VALUES performs this operation quite simply and efficiently with just a single pass of the table (unlike union queries that do one pass for every column)
SELECT
ca.ColName, ca.ColValue
FROM YOurTable
CROSS APPLY (
Values
('ScripName' , ScripName),
('ScripCode' , ScripCode),
('Price' , cast(Price as varchar(50)) )
) as CA (ColName, ColValue)
Personally I find this syntax easier than using unpivot.
NB: You must take care that all source columns are converted into compatible types for the single value column
DECLARE #TABLE TABLE
(RowNo INT,ScripName VARCHAR(10),ScripCode VARCHAR(10)
,Price VARCHAR(10))
INSERT INTO #TABLE VALUES
(1,'20 MICRONS ','533022','39')
SELECT ColumnName,ColumnValue from #Table
Unpivot(ColumnValue For ColumnName IN (ScripName,ScripCode,Price)) AS H
i solved the query this way
SELECT
ca.ID, ca.[Name]
FROM [Emp2]
CROSS APPLY (
Values
('ID' , cast(ID as varchar)),
('[Name]' , Name)
) as CA (ID, Name)
output look like
ID Name
------ --------------------------------------------------
ID 1
[Name] Joy
ID 2
[Name] jean
ID 4
[Name] paul
CREATE TABLE #ORIGINAL
(
COUNTRY VARCHAR(50),
MALE_CRICKETER VARCHAR(50),
FEMALE_CRICKETER VARCHAR(50),
MALE_STAR VARCHAR(50),
FEMALE_STAR VARCHAR(50),
)
select * from #ORIGINAL
SELECT COUNTRY, ca.GENDER, ca.STAR, ca.CRICKETR
FROM #ORIGINAL
CROSS APPLY (
Values
('M', MALE_CRICKETER, MALE_STAR),
('F', FEMALE_CRICKETER, FEMALE_STAR)
) as CA (GENDER, CRICKETR, STAR)
Related
I have an interesting situation in SQL Server 2016. I am using T-SQL language.
I have a dataset called (#dataset):
The last column called ContinuousDates will ALWAYS have continuous date values without a gap, say Jan 1, 2021 to Dec 31, 2021. It will NEVER have duplicate dates for the same ID or Name, i.e. one person on a given day can have only one row of data. (In this example, I am showing just one person, with ID = 1 and Name = X. In my actual data, I have multiple people).
Note that NYC city occurs earlier in the dataset, and gets repeated in the last 4 rows.
I need to obtain the below dataset based on date range:
I tried to use a simple MINIMUM and MAXIMUM on the dataset, but I realize that at times I can get a wrong output, as below:
I tried some options using RANK() and DENSE_RANK() functions, but am not able to come to a solution. Can someone provide me assistance ?
I have the codes attached here:
CREATE TABLE #dataset
(
ID int,
Name varchar(20),
City varchar(20),
ContinuousDates date
)
INSERT INTO #dataset
VALUES(1,'X','NYC','1/1/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/2/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/3/2021')
INSERT INTO #dataset
VALUES(1,'X','SFO','1/4/2021')
INSERT INTO #dataset
VALUES(1,'X','SFO','1/5/2021')
INSERT INTO #dataset
VALUES(1,'X','PHY','1/6/2021')
INSERT INTO #dataset
VALUES(1,'X','PHY','1/7/2021')
INSERT INTO #dataset
VALUES(1,'X','PHY','1/8/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/9/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/10/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/11/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/12/2021')
SELECT *
FROM #dataset
ORDER BY ContinuousDates
I have a new set of codes, for a better demonstration:
CREATE TABLE #dataset
(
ID int,
Name varchar(20),
City varchar(20),
ContinuousDates date
)
INSERT INTO #dataset
VALUES(1,'X','NYC','1/1/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/2/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/3/2021')
INSERT INTO #dataset
VALUES(1,'X','SFO','1/4/2021')
INSERT INTO #dataset
VALUES(1,'X','SFO','1/5/2021')
INSERT INTO #dataset
VALUES(1,'X','PHY','1/6/2021')
INSERT INTO #dataset
VALUES(1,'X','PHY','1/7/2021')
INSERT INTO #dataset
VALUES(1,'X','PHY','1/8/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/9/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/10/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/11/2021')
INSERT INTO #dataset
VALUES(1,'X','NYC','1/12/2021')
INSERT INTO #dataset
VALUES(2,'Y','MEL','1/13/2021')
INSERT INTO #dataset
VALUES(3,'Z','SYD','1/14/2021')
INSERT INTO #dataset
VALUES(3,'Z','SYD','1/15/2021')
INSERT INTO #dataset
VALUES(3,'Z','PER','1/16/2021')
INSERT INTO #dataset
VALUES(4,'A',NULL,'1/16/2021')
INSERT INTO #dataset
VALUES(4,'A', NULL,'1/17/2021')
SELECT *
FROM #dataset
ORDER BY ID, ContinuousDates
Solution steps:
numbers sections with ID and Name sorted by date (row_id)
numbers sections with ID, Name and City sorted by date (p_row_id)
calculate row_id - p_row_id
Now you have group numbers for each period within unique set of values.
All that you need is to group by this number, ID, Name and City
ID
Name
City
ContinuousDates
p_row_id
row_id
row_id - p_row_id
1
X
NYC
2021-01-01
1
1
0
1
X
NYC
2021-01-02
2
2
0
1
X
NYC
2021-01-03
3
3
0
1
X
SFO
2021-01-04
1
4
3
1
X
SFO
2021-01-05
2
5
3
1
X
PHY
2021-01-06
1
6
5
1
X
PHY
2021-01-07
2
7
5
1
X
PHY
2021-01-08
3
8
5
1
X
NYC
2021-01-09
4
9
5
1
X
NYC
2021-01-10
5
10
5
1
X
NYC
2021-01-11
6
11
5
1
X
NYC
2021-01-12
7
12
5
select
CD.ID
,CD.[Name]
,CD.City
,min(CD.ContinuousDates) as DateStart
,max(CD.ContinuousDates) as DateEnd
from
(
select *
,row_number() over(partition by CD.ID, CD.[Name], CD.City order by CD.ContinuousDates) as p_row_id
,row_number() over(partition by CD.ID, CD.[Name] order by CD.ContinuousDates) as row_id
from #dataset CD
) CD
group by CD.row_id - CD.p_row_id
,CD.ID
,CD.[Name]
,CD.City
order by DateStart
template for multiple column:
select
CD.GroupColumn1
,CD.GroupColumn2
..
,CD.Column1
,CD.Column2
,CD.Column3
,CD.Column4
..
,min(CD.ContinuousDates) as DateStart
,max(CD.ContinuousDates) as DateEnd
from
(
select *
,row_number() over(partition by
CD.GroupColumn1
,CD.GroupColumn2
..
,CD.Column1
,CD.Column2
,CD.Column3
,CD.Column4
..
order by CD.ContinuousDates) as p_row_id
,row_number() over(partition by
CD.GroupColumn1
,CD.GroupColumn2
..
order by CD.ContinuousDates) as row_id
from #dataset CD
) CD
group by CD.row_id - CD.p_row_id
,CD.GroupColumn1
,CD.GroupColumn2
..
CD.Column1
,CD.Column2
,CD.Column3
,CD.Column4
..
order by DateStart
This is a type of gaps-and-islands problem.
There are a number of different solutions. Here is one simple one
Use LAG to identify rows that start each island
A running conditional count gives us an ID for each island
Then simply group up by that ID (along with any other partition columns)
WITH StartPoints AS (
SELECT *,
IsStart = CASE WHEN LAG(City, 1, '') OVER (PARTITION BY ID ORDER BY ContinuousDates)
<> City THEN 1 END
FROM #dataset ds
),
Groups AS (
SELECT *,
GroupId = COUNT(IsStart) OVER (PARTITION BY ID ORDER BY ContinuousDates ROWS UNBOUNDED PRECEDING)
FROM StartPoints
)
SELECT
ID,
Name,
City = MIN(City),
DateStart = MIN(ContinuousDates),
DateEnd = MAX(ContinuousDates)
FROM Groups
GROUP BY
ID,
Name,
GroupId;
db<>fiddle
I have a scenario where I need to convert columns of table to rows
eg -
table - stocks:
ScripName ScripCode Price
-----------------------------------------
20 MICRONS 533022 39
I need to represent the table in the following format, but I just need this kind of representation for single row
ColName ColValue
-----------------------------
ScripName 20 MICRONS
ScripCode 533022
Price 39
so that I can directly bind the data to the datalist control.
Sound like you want to UNPIVOT
Sample from books online:
--Create the table and insert values as portrayed in the previous example.
CREATE TABLE pvt (VendorID int, Emp1 int, Emp2 int,
Emp3 int, Emp4 int, Emp5 int);
GO
INSERT INTO pvt VALUES (1,4,3,5,4,4);
INSERT INTO pvt VALUES (2,4,1,5,5,5);
INSERT INTO pvt VALUES (3,4,3,5,4,4);
INSERT INTO pvt VALUES (4,4,2,5,5,4);
INSERT INTO pvt VALUES (5,5,1,5,5,5);
GO
--Unpivot the table.
SELECT VendorID, Employee, Orders
FROM
(SELECT VendorID, Emp1, Emp2, Emp3, Emp4, Emp5
FROM pvt) p
UNPIVOT
(Orders FOR Employee IN
(Emp1, Emp2, Emp3, Emp4, Emp5)
)AS unpvt;
GO
Returns:
VendorID Employee Orders
---------- ---------- ------
1 Emp1 4
1 Emp2 3
1 Emp3 5
1 Emp4 4
1 Emp5 4
2 Emp1 4
2 Emp2 1
2 Emp3 5
2 Emp4 5
2 Emp5 5
see also: Unpivot SQL thingie and the unpivot tag
declare #T table (ScripName varchar(50), ScripCode varchar(50), Price int)
insert into #T values ('20 MICRONS', '533022', 39)
select
'ScripName' as ColName,
ScripName as ColValue
from #T
union all
select
'ScripCode' as ColName,
ScripCode as ColValue
from #T
union all
select
'Price' as ColName,
cast(Price as varchar(50)) as ColValue
from #T
select 'ScriptName', scriptName from table
union all
select 'ScriptCode', scriptCode from table
union all
select 'Price', price from table
As an alternative:
Using CROSS APPLY and VALUES performs this operation quite simply and efficiently with just a single pass of the table (unlike union queries that do one pass for every column)
SELECT
ca.ColName, ca.ColValue
FROM YOurTable
CROSS APPLY (
Values
('ScripName' , ScripName),
('ScripCode' , ScripCode),
('Price' , cast(Price as varchar(50)) )
) as CA (ColName, ColValue)
Personally I find this syntax easier than using unpivot.
NB: You must take care that all source columns are converted into compatible types for the single value column
DECLARE #TABLE TABLE
(RowNo INT,ScripName VARCHAR(10),ScripCode VARCHAR(10)
,Price VARCHAR(10))
INSERT INTO #TABLE VALUES
(1,'20 MICRONS ','533022','39')
SELECT ColumnName,ColumnValue from #Table
Unpivot(ColumnValue For ColumnName IN (ScripName,ScripCode,Price)) AS H
i solved the query this way
SELECT
ca.ID, ca.[Name]
FROM [Emp2]
CROSS APPLY (
Values
('ID' , cast(ID as varchar)),
('[Name]' , Name)
) as CA (ID, Name)
output look like
ID Name
------ --------------------------------------------------
ID 1
[Name] Joy
ID 2
[Name] jean
ID 4
[Name] paul
CREATE TABLE #ORIGINAL
(
COUNTRY VARCHAR(50),
MALE_CRICKETER VARCHAR(50),
FEMALE_CRICKETER VARCHAR(50),
MALE_STAR VARCHAR(50),
FEMALE_STAR VARCHAR(50),
)
select * from #ORIGINAL
SELECT COUNTRY, ca.GENDER, ca.STAR, ca.CRICKETR
FROM #ORIGINAL
CROSS APPLY (
Values
('M', MALE_CRICKETER, MALE_STAR),
('F', FEMALE_CRICKETER, FEMALE_STAR)
) as CA (GENDER, CRICKETR, STAR)
Convert two column to rows in SQL Server
by Simple Cross Apply
DECLARE #Table1 TABLE
(ID int,installdate varchar(20),uninstalldate varchar(20))
;
INSERT INTO #Table1
(ID,installdate,uninstalldate)
VALUES
(1,'15/06/2016','18/06/2016'),
(2,'20/06/2016','25/06/2016')
Script :
select COL AS [Instal OR Uninstall],VAL AS [Date] from #Table1
CROSS APPLY
(VALUES
('installdate',installdate),
('uninstalldate',installdate))
CS(COL,VAL)
Simple UNPIVOT should do thing:
SELECT [DATES],
[VALUES]
FROM MyTable
UNPIVOT (
[VALUES] FOR [DATES] IN (InstallDate,UnInstallDate)
) as unpvt
Output:
DATES VALUES
InstallDate 2016-06-15
UnInstallDate 2016-06-18
InstallDate 2016-06-20
UnInstallDate 2016-06-25
You can UNPIVOT the columns into rows:
DECLARE #Data TABLE (
Id INT,
InstallDate DATE,
UnInstallDate DATE
)
INSERT #Data VALUES (1,'6/15/2016', '6/18/2016'),(2,'6/20/2016', '6/25/2016')
SELECT
ActivityType,
ActivityDate
FROM #Data
UNPIVOT (ActivityDate FOR ActivityType IN (InstallDate, UnInstallDate)) T
This produces the following rows:
ActivityType ActivityDate
------------------------- ------------
InstallDate 2016-06-15
UnInstallDate 2016-06-18
InstallDate 2016-06-20
UnInstallDate 2016-06-25
i'm stuck with a query and i don't want to use a while loop or another nasty method to do this.
Here's the situation:
I've got a query that gets some data, and i need to calculate a column based on 2 other columns.
My results are as follow:
Type | Customer | Cycle | Amount | Expiration | Row_Number (Partition By Customer, Cycle)
So, my row_number column needs to "group" customers and cycles, here's a Fiddle to better understand it
Here's an example:
As you can see, iteration column is correctly applied as far as i know what row_number does.
But i need to do this:
Is there a way to do this with Row_Number ?
or should i need store the data in a temp table, loop through it and update this ITERATION column?
Maybe a CTE?
Any help on this will be highly appreciated. Thanks!
just run this as new query, replace what you need in your query...
WITH T(StyleID, ID)
AS (SELECT 1,1 UNION ALL
SELECT 1,1 UNION ALL
SELECT 1,1 UNION ALL
SELECT 1,2)
SELECT *,
RANK() OVER(PARTITION BY StyleID ORDER BY ID) AS 'RANK',
ROW_NUMBER() OVER(PARTITION BY StyleID ORDER BY ID) AS 'ROW_NUMBER',
DENSE_RANK() OVER(PARTITION BY StyleID ORDER BY ID) AS 'DENSE_RANK'
FROM T
regards,
Valentin
You could use DENSE_RANK function instead of ROW_NUMBER.
DECLARE #MyTable TABLE
(
Customer NVARCHAR(100) NOT NULL,
[Cycle] SMALLINT NOT NULL
);
INSERT #MyTable VALUES ('C1', 2010);
INSERT #MyTable VALUES ('C1', 2010);
INSERT #MyTable VALUES ('C1', 2011);
INSERT #MyTable VALUES ('C1', 2012);
INSERT #MyTable VALUES ('C1', 2012);
INSERT #MyTable VALUES ('C1', 2012);
INSERT #MyTable VALUES ('C2', 2010);
INSERT #MyTable VALUES ('C2', 2010);
SELECT t.Customer, t.[Cycle],
DENSE_RANK() OVER(PARTITION BY t.Customer ORDER BY t.[Cycle]) AS Rnk
FROM #MyTable t
ORDER BY Customer, [Cycle];
Results:
Customer Cycle Rnk
-------- ------ ---
C1 2010 1
C1 2010 1
C1 2011 2
C1 2012 3
C1 2012 3
C1 2012 3
C2 2010 1
C2 2010 1
SQL Fiddle
Suppose i have two tables
declare #emp table
(
EmpID int,
EmpName varchar(10)
)
declare #Remu table
(
EmpID int,
Sal Decimal(10,2),
PaidYear varchar(10)
)
I want maximum salary grouped on PaidYear (With Ties)
Expected OUTPUT
EmpID EmpName PaidYear Sal
1 Jon 2001 2000
2 Smith 2001 2000
3 Nash 2003 4000
4 Hoge 2005 5000
5 Peter 2005 5000
I have an issue when using Join
select e.EmpID,e.EmpName,r.Sal,r.PaidYear from #emp e
inner join
(select max(Sal) as Sal,PaidYear from #Remu group by PaidYear)r
on e.EmpID=???
when i select EmpID in
select max(Sal) as Sal,PaidYear from #Remu group by PaidYear
i have to Group by PaidYear and EmpID,which won't give the desired result as i expected.
How to solve this.I want a query which should be compatible with SQL Server 2000.
select e.EmpID,e.EmpName,r.Sal,r.PaidYear
from #emp e inner join #Remu r on e.EmpId = r.EmpId
where r.sal in (select max(sal) from #remu group by paidyear)
Each year needs to determine a single max salary specific to that year.
select e.EmpID
, e.EmpName
, r.Sal
, r.PaidYear
from #emp as e
inner join #Remu as r
on e.EmpId = r.EmpId
where r.sal = (select max(sal)
from #remu
where paidyear = r.PaidYear ' makes it year specific
)
Data To Test:
declare #emp table
(
EmpID int,
EmpName varchar(10)
)
declare #Remu table
(
EmpID int,
Sal Decimal(10,2),
PaidYear varchar(10)
)
insert into #emp (EmpID, EmpName)
values(1, 'Jon')
insert into #emp (EmpID, EmpName)
values(2, 'Smith')
insert into #emp (EmpID, EmpName)
values(3, 'Nash')
insert into #emp (EmpID, EmpName)
values(4, 'Hoge')
insert into #emp (EmpID, EmpName)
values(5, 'Peter')
Insert into #Remu (EmpID, Sal, PaidYear)
values(1, 2000, '2001')
Insert into #Remu (EmpID, Sal, PaidYear)
values(2, 4999, '2001')
Insert into #Remu (EmpID, Sal, PaidYear)
values(2, 8000, '2003')
Insert into #Remu (EmpID, Sal, PaidYear)
values(3,4000, '2003')
Insert into #Remu (EmpID, Sal, PaidYear)
values(4, 5000, '2005')
Insert into #Remu (EmpID, Sal, PaidYear)
values(5, 4999, '2005')
Results:
EmpID EmpName Sal PaidYear
4 Hoge 5000.00 2005
2 Smith 8000.00 2003
2 Smith 4999.00 2001