I have a table
name | age | city
-------------
joe | 42 | berlin
ben | 42 | munich
anna | 22 | hamburg
pia | 50 | berlin
georg | 42 | munich
lisa | 42 | berlin
Now I would like to get all 42 year old in different columns by city
berlin | munich
-------------
joe | ben
lisa | georg
So I would need something like
SELECT (
SELECT name AS berlin WHERE city = "berlin"
UNION
SELECT name AS munich WHERE city = "munich")
FROM TABLE
WHERE
age = 42
Best from Berlin
Joerg
I think you want aggregation:
select max(case when city = 'berlin' then name end) as berlin,
max(case when city = 'munich' then name end) as munich
from (select t.*, row_number() over (partition by city order by name) as seqnum
from t
where city in ('berlin', 'munich') and age = 42
) t
group by seqnum
order by seqnum;
Using PIVOT for example I did it with SQL Server. Hope this can help you.
DECLARE #columns varchar(MAX);
DECLARE #sql nvarchar(max)
CREATE TABLE #Table
(
idPerson int,
firstName varchar(10),
age int,
city varchar(10)
);
INSERT INTO #Table
SELECT '1', 'joe', '42','berlin' UNION ALL
SELECT '2', 'ben', '42','munich' UNION ALL
SELECT '3', 'Ana', '22','hamburg' UNION ALL
SELECT '4', 'pia', '50','berlin' UNION ALL
SELECT '5', 'george', '42','munich' UNION ALL
SELECT '6', 'lisa', '42','munich'
--SELECT * from #Table
SET #columns = STUFF(
(
SELECT
',' + QUOTENAME(LTRIM(city))
FROM
(SELECT DISTINCT city
FROM #Table
) AS T
ORDER BY
city
FOR XML PATH('')
), 1, 1, '');
SET #sql = N'
SELECT
*
FROM
(
SELECT idPerson ,firstName ,age ,city
FROM #Table
--WHERE age = 42
) AS T
PIVOT
(
MAX(firstName)
FOR city IN (' + #columns + N')
) AS P order by age;';
EXEC sp_executesql #sql;
DROP TABLE #Table;
Thanks for your help! Based on the answer of Gordon Linhoff I got this solution:
SELECT max(case when city = 'berlin' then name end) as berlin,
max(case when city = 'munich' then name end) as munich
FROM TABLE
WHERE age = 42
;
Related
I have a table sales:
SalesID. Date. Geography
1. 2020-01. Italy
1. 2020-01. France
1. 2020-01. UK
2. 2020-02. Italy
2. 2002-02. Canada
3. 2002-08. France
I would like to have a result like this:
SalesID. Date. Geography1 Geography2. Geography3
1. 2020-01. Italy. France. Uk
2. 2020-02. Italy. Canada. Null
3. 2020-08. France
I know how to do pivot the column but the number of Geography is unlimited for a sales id. How to do this?
;WITH L AS(
SELECT SalesID, Date, Geography
from
(
SELECT 1 as SalesID, '2020-01' as Date, 'Italy' as Geography
UNION ALL
SELECT 1, '2020-01', 'France'
UNION ALL
SELECT 1, '2020-01', 'UK'
UNION ALL
SELECT 2, '2020-02', 'Italy'
UNION ALL
SELECT 2, '2020-02', 'Canada'
UNION ALL
SELECT 3, '2002-08', 'France'
)S
),
L1 AS(
SELECT SalesID, Date, Geography
from
(
SELECT 1 as SalesID, '2020-01' as Date, 'Italy' as Geography
UNION ALL
SELECT 1, '2020-01', 'France'
UNION ALL
SELECT 1, '2020-01', 'UK'
UNION ALL
SELECT 2, '2020-02', 'Italy'
UNION ALL
SELECT 2, '2020-02', 'Canada'
UNION ALL
SELECT 3, '2002-08', 'France'
)S
)
SELECT
L.SalesID,L.Date,
STUFF((SELECT '; ' + L1.Geography
FROM L1
WHERE L1.SalesID = L.SalesID
AND L1.Date = L.Date
FOR XML PATH('')), 1, 1, '') [Geography]
FROM L
GROUP BY L.SalesID, L.Date
ORDER BY 1
Here the Output of the SQL Query as a screenshot:
CREATE TABLE MyTable(
SalesID INT,
[Date] varchar(20),
Geography VARCHAR(50)
);
INSERT INTO MyTable(SalesID,[Date],Geography)VALUES
(1,'2020-01','Italy'),(1,'2020-01','France'),
(1,'2020-01','UK'),(2,'2020-02','Italy'),(2,'2020-02','Canada'),
(3,'2020-08','France');
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(a.Geography)
FROM MyTable a
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT date, ' + #cols + ' from
(
select
SalesID
,Date
, Geography
from MyTable
) x
pivot
(
max(Geography)
for Geography in (' + #cols + ')
) p '
execute(#query)
date | Canada | France | Italy | UK
:------ | :----- | :----- | :---- | :---
2020-01 | null | France | Italy | UK
2020-02 | Canada | null | Italy | null
2020-08 | null | France | null | null
db<>fiddle here
I have the following table:
id Prefix FisrtName LastName
--------------------------------------------
123 Mr Lynn Berg
123 Ms Madeline Owen
123 Mrs Zelenia Sellers
101 Mrs Jesse Vincent
101 Mr Chaim Long
The result table should look like this
id name1 name2 name2
-----------------------------------------------------------
123 Mr Lynn Berg Ms MadelineOwen Mrs Zelenia Sellers
101 Mrs Jesse Vincent Mr Chaim Long
How could I achieve this result in SQL Server? Can I use pivot function?
Please help
You can also do conditional aggregation :
select id, max(case when seq = 1 then Name end) as Name1,
max(case when seq = 2 then Name end) as Name2,
max(case when seq = 3 then Name end) as Name3
from (select id, concat(Prefix,' ',FisrtName,' ',LastName) as Name,
row_number() over (partition by id order by (select null)) as seq
from table
) t
group by id;
Try this simple pivot:
declare #tbl table (id int, Prefix varchar(3), FirstName varchar(20), LastName varchar(20));
insert into #tbl values
(123, 'Mr', 'Lynn', 'Berg'),
(123, 'Ms', 'Madeline', 'Owen'),
(123, 'Mrs', 'Zelenia', 'Sellers'),
(101, 'Mrs', 'Jesse', 'Vincent'),
(101, 'Mr', 'Chaim', 'Long');
select id, [1] [Name1], [2] [Name2], [3] [Name3] from (
select id,
ROW_NUMBER() over (partition by id order by (select null)) rn,
Prefix + ' ' + FirstName + ' ' + LastName [FullName]
from #tbl
) a pivot (
max(fullname) for rn in ([1],[2],[3])
) b;
CREATE TABLE #Table1 (
id INT
,Prefix VARCHAR(3)
,FisrtName VARCHAR(8)
,LastName VARCHAR(7)
);
INSERT INTO #Table1
VALUES (
123
,'Mr'
,'Lynn'
,'Berg'
)
,(
123
,'Ms'
,'Madeline'
,'Owen'
)
,(
123
,'Mrs'
,'Zelenia'
,'Sellers'
)
,(
101
,'Mrs'
,'Jesse'
,'Vincent'
)
,(
101
,'Mr'
,'Chaim'
,'Long'
)
SELECT *
FROM #Table1
SELECT id
,[1] [Name1]
,[2] [Name2]
,[3] [Name3]
FROM (
SELECT id
,CONCAT (
PREFIX
,FISRTNAME
,LASTNAME
) AS Namm
,ROW_NUMBER() OVER (
PARTITION BY id ORDER BY (
id
)
) AS rn
FROM #TABLE1
) a
pivot(max(Namm) FOR rn IN (
[1]
,[2]
,[3]
)) b
I have a table in this form:
id | firstname | lastname | userid
---+-----------+------------------------
1 | john | smith | 545868-5434-343435-35353
2 | adam | finger | 545868-5434-343435-35353
3 | teri | marti | 545868-5434-343435-35353
4 | pei | port | 545868-5434-343435-35353
In the DB i have many userid i need to populate the very same firstname and lastname to all userid found in the Database
Here is my SQl Query
SELECT
cID, c.firstname,c.lastname,
[s].UserID,c.OwnerID
FROM
Customer INNER JOIN [s] ON c.OwnerID = [s].UserID AND c.AssignedtoID =
[s].UserID AND c.CreatedByUserID = [s].UserID
AssignedtoID is the same as UserID
is this helpful for you.?
Create table #tmpCustomer (id int, firstname VARCHAR(50),lastname VARCHAR(50),userid VARCHAR(100))
INSERT INTO #tmpCustomer
SELECT 1, 'john','smith','545868-5434-343435-35353'
union
SELECT 2,'adam','finger','545868-5434-343435-35353'
union
SELECT 3,'teri','marti','545868-5434-343435-35353'
union
SELECT 4, 'pei','port','545868-5434-343435-35353'
union
SELECT 5, 'abc','xyz','545868-5434-343435-35354'
union
SELECT 6, 'mno','ert','545868-5434-343435-35354'
--select * from #tmpCustomer
;with cte1 AS(Select row_number()over(partition by userid order by id) rn,* from #tmpCustomer ),
cte2 AS (select * from cte1 where rn=1 )
update t
set t.firstname=c.firstname
from #tmpCustomer t
JOIN cte2 c on t.userid=c.userid
select * from #tmpCustomer
drop table #tmpCustomer
i don't know if i good understand your question, try solution posted below
DECLARE #cust as table (firstname varchar(20),lastname Varchar(20))
Insert #cust
values
('Suzan','Smith')
declare #id as table (id int identity,anything varchar(20),row_inserted datetime2 default (cast(sysdatetime() as datetime2)))
INSERT #id
(anything,row_inserted)
SELECT 'x' ,'20180305'
union all
select 'y','20180305'
union all
select 'z','20180305'
select s.id,c.firstname,
c.lastname
from #id as s
cross join #cust as c
I have a procedure that returns the following table:
And I want to pivot it around so that for each Name that is returned, you have a row for Planned, Actual and Difference.
For example:
| Key | Name1 | Name2 | Name3 | Name4
| Planned | 0 | 0 | 0 | 0
| Actual | 8957 | 5401 | NULL | NULL
|Difference| -8957 | -5401 | NULL | NULL
I'm trying to use the PIVOT function, but I've never used it before and am struggling to get my head around it. How would one achieve something similar to the above?
Without a pivot, you can use a cross join instead
Note this only works if you know how many names you will have everytime you run it and if each name only appears once in the original table.(otherwise the max function below is not appropriate)
create table #test(ID int, Name char(5), planned int, actual int, difference_between int)
insert into dbo.#test
values
(54, 'Name1', 0, 8975, -8957),
(54, 'Name2', 0, 5401, -5401),
(54, 'Name3', 0, NULL, NULL),
(54, 'Name4', 0, NULL, NULL)
select case t.occurno when 1 then 'Planned' when 2 then 'Actual' when 3 then 'Difference' end as [Key]
, max(case when Name = 'name1' then case t.occurno when 1 then planned when 2 then actual when 3 then difference_between else 0 end end) as Name1
, max(case when Name = 'name2' then case t.occurno when 1 then planned when 2 then actual when 3 then difference_between else 0 end end) as name2
, max(case when Name = 'name3' then case t.occurno when 1 then planned when 2 then actual when 3 then difference_between else 0 end end) as name3
, max(case when Name = 'name4' then case t.occurno when 1 then planned when 2 then actual when 3 then difference_between else 0 end end) as name4
from dbo.#test
cross join
(select top 3 ROW_NUMBER() over(order by occurno) as occurno
from (select 1 as occurno) t
group by cube(occurno,occurno,occurno,occurno)
) t
group by t.occurno
create table #T
(
Name varchar(255),
Planned int,
Actual int,
[Difference] int
)
insert into #T(Name, Planned, Actual, [Difference])
select 'Name1', 0, 8957, -8957
union
select 'Name2', 0, 5401, -5401
union
select 'Name3', 0, NULL, NULL
union
select 'Name4', 0, NULL, NULL
-- unpivoting data
create table #T2
(
[Key] varchar(255),
Name varchar(255),
Value int
)
insert into #T2
select [Key], Name, Value
from
(select Name, Planned, Actual, [Difference] from #T) P
UNPIVOT
(Value for [Key] IN (Planned, Actual, [Difference])) as UNP
-- getting sequence of column names
declare #columns nvarchar(max)
set #columns = ''
select #columns = #columns + ', [' + Name + ']'
from (select distinct Name from #T2) as T
order by Name
set #columns = substring(#columns, 2, len(#columns))
declare #sql nvarchar(max)
-- building dynamic sql for pivoting
set #sql =
'
SELECT *
FROM
(SELECT
[Key], Name, Value
FROM
#T2
) AS SourceTable
PIVOT
(
SUM(Value)
FOR Name in ('+#columns+')
) AS PivotTable
order by
case [Key]
when ''Planned'' then 1
when ''Actual'' then 2
when ''Difference'' then 3 end
'
exec sp_executeSQL #SQL
drop table #T2
drop table #T
I have table like this
Reg_No Student_Name Subject1 Subject2 Subject3 Subject4 Total
----------- -------------------- ----------- ----------- ----------- ----------- -----------
101 Kevin 85 94 78 90 347
102 Andy 75 88 91 78 332
From this I need to create a temp table or table like this:
Reg_No Student_Name Subject Total
----------- -------------------- ----------- -----------
101 Kevin 85 347
94
78
90
102 Andy 75 332
88
91
78
Is there a way I can do this in SQL Server?
DDL:
DECLARE #temp TABLE
(
Reg_No INT
, Student_Name VARCHAR(20)
, Subject1 INT
, Subject2 INT
, Subject3 INT
, Subject4 INT
, Total INT
)
INSERT INTO #temp (Reg_No, Student_Name, Subject1, Subject2, Subject3, Subject4, Total)
VALUES
(101, 'Kevin', 85, 94, 78, 90, 347),
(102, 'Andy ', 75, 88, 91, 78, 332)
Query #1 - ROW_NUMBER:
SELECT Reg_No = CASE WHEN rn = 1 THEN t.Reg_No END
, Student_Name = CASE WHEN rn = 1 THEN t.Student_Name END
, t.[Subject]
, Total = CASE WHEN rn = 1 THEN t.Total END
FROM (
SELECT
Reg_No
, Student_Name
, [Subject]
, Total
, rn = ROW_NUMBER() OVER (PARTITION BY Reg_No ORDER BY 1/0)
FROM #temp
UNPIVOT
(
[Subject] FOR tt IN (Subject1, Subject2, Subject3, Subject4)
) unpvt
) t
Query #2 - OUTER APPLY:
SELECT t.*
FROM #temp
OUTER APPLY
(
VALUES
(Reg_No, Student_Name, Subject1, Total),
(NULL, NULL, Subject2, NULL),
(NULL, NULL, Subject3, NULL),
(NULL, NULL, Subject4, NULL)
) t(Reg_No, Student_Name, [Subject], Total)
Query Plan:
Query Cost:
Output:
Reg_No Student_Name Subject Total
----------- -------------------- ----------- -----------
101 Kevin 85 347
NULL NULL 94 NULL
NULL NULL 78 NULL
NULL NULL 90 NULL
102 Andy 75 332
NULL NULL 88 NULL
NULL NULL 91 NULL
NULL NULL 78 NULL
PS: In your case query with OUTER APPLY is faster than ROW_NUMBER solution.
The simplest approach would be to use a UNIONclause
select Reg_No, Student_Name, Subject1, Total from YourTable union all
select Reg_No, Student_Name, Subject2, Total from YourTable union all
select Reg_No, Student_Name, Subject3, Total from YourTable union all
select Reg_No, Student_Name, Subject3, Total from YourTable
UNION
Combines the results of two or more queries into a single result set
that includes all the rows that belong to all queries in the union.
The UNION operation is different from using joins that combine columns
from two tables.
The following are basic rules for combining the result sets of two
queries by using UNION:
•The number and the order of the columns must be the same in all
queries.
•The data types must be compatible.
Check this Fiddle
;WITH MyCTE AS
(
SELECT *
FROM (
SELECT Reg_No,
[Subject1],
[Subject2],
[Subject3],
[Subject4]
FROM Table1
)p
UNPIVOT
(
Result FOR SubjectName in ([Subject1], [Subject2], [Subject3], [Subject4])
)unpvt
)
SELECT T.Reg_No,
T.Student_Name,
M.SubjectName,
M.Result,
T.Total
FROM Table1 T
JOIN MyCTE M
ON T.Reg_No = M.Reg_No
If you do want NULL values in the rest, you may try the following:
This is the new Fiddle
And here is the code:
;WITH MyCTE AS
(
SELECT *
FROM (
SELECT Reg_No,
[Subject1],
[Subject2],
[Subject3],
[Subject4]
FROM Table1
)p
UNPIVOT
(
Result FOR SubjectName in ([Subject1], [Subject2], [Subject3], [Subject4])
)unpvt
),
MyNumberedCTE AS
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY Reg_No ORDER BY Reg_No,SubjectName) AS RowNum
FROM MyCTE
)
SELECT T.Reg_No,
T.Student_Name,
M.SubjectName,
M.Result,
T.Total
FROM MyCTE M
LEFT JOIN MyNumberedCTE N
ON N.Reg_No = M.Reg_No
AND N.SubjectName = M.SubjectName
AND N.RowNum=1
LEFT JOIN Table1 T
ON T.Reg_No = N.Reg_No
You should look after the PIVOT operator :
http://technet.microsoft.com/en-us/library/ms177410(v=sql.100).aspx
> DECLARE #cols AS NVARCHAR(MAX),#query AS NVARCHAR(MAX)
>
> select #cols = STUFF((SELECT ',' + QUOTENAME(designation)
> from MyTable
> group by designation
> order by designation
> FOR XML PATH(''), TYPE
> ).value('.', 'NVARCHAR(MAX)'),1,1,'')
>
> set #query = N'SELECT Row, ' + #cols + N' from
> (
> select ''SS'' Row, SS AS Value , designation from MyTable
> UNION ALL
> select ''AS'' Row, [AS] AS Value , designation from MyTable
> UNION ALL
> select ''Vac'' Row, Vac AS Value , designation from MyTable
> ) x
> pivot
> (
> max(Value) for designation in (' + #cols + N')
> ) p '
> exec sp_executesql #query;
For more details: Convert row into column when number of row is not fixed