Transpose rows to columns in SQL Server - sql

is there a way to transpose this table:
A a
A b
A c
A d
B e
B f
C g
C h
C i
to this?
A B C
a e g
b f h
c i
d
Many thanks!

You can do this using ROW_NUMBER and conditional aggregation:
WITH Cte AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col2)
FROM #tbl
)
SELECT
A = MAX(CASE WHEN col1 = 'A' THEN col2 END),
B = MAX(CASE WHEN col1 = 'B' THEN col2 END),
C = MAX(CASE WHEN col1 = 'C' THEN col2 END)
FROM Cte
GROUP BY rn
ONLINE DEMO

Dynamic sql version for Felix Pamittan's answer
Query
DECLARE #sql AS VARCHAR(MAX);
SELECT #sql = 'WITH Cte AS(
SELECT *, rn = ROW_NUMBER() OVER(
PARTITION BY col1 ORDER BY col2
)
FROM your_table_name
) SELECT '
+ STUFF((
SELECT DISTINCT
',COALESCE(MAX(CASE col1 WHEN ''' + col1 + ''' THEN col2 END), '''') AS [' + col1 + ']'
FROM your_table_name
FOR XML PATH('')), 1, 1, '');
SELECT #sql += ' FROM cte GROUP BY rn;';
EXEC(#sql);
Result
+---+---+---+
| A | B | C |
+---+---+---+
| a | e | g |
| b | f | h |
| c | | i |
| d | | |
+---+---+---+
Find demo here

Related

Need help in creating a view with following data

I have a table like
A | All,
B | X,
C | Y,
D | Z
so I have to create a view replacing all with rest of the values in column.
So my desired output will be
A | X,
A | Y,
A | Z,
B | X,
C | Y,
D | Z
Thanks in advance!
Here is one way
SELECT col1,
col2
FROM (SELECT DISTINCT col2
FROM Yourtable
WHERE col2 <> 'All') a
CROSS JOIN (SELECT col1
FROM Yourtable
WHERE col2 = 'All') b
UNION ALL
SELECT col1,
col2
FROM Yourtable
WHERE col2 <> 'All'

How to comapre two columns of a table in sql?

In a table there are two columns:
-----------
| A | B |
-----------
| 1 | 5 |
| 2 | 1 |
| 3 | 2 |
| 4 | 1 |
-----------
Want a table where if A=B then
-------------------
|Match | notMatch|
-------------------
| 1 | 5 |
| 2 | 3 |
| Null | 4 |
-------------------
How can i do this?
I tried something which shows the Matched part
select distinct C.A as A from Table c inner join Table d on c.A=d.B
Try this:
;WITH TempTable(A, B) AS(
SELECT 1, 5 UNION ALL
SELECT 2, 1 UNION ALL
SELECT 3, 2 UNION ALL
SELECT 4, 1
)
,CTE(Val) AS(
SELECT A FROM TempTable UNION ALL
SELECT B FROM TempTable
)
,Match AS(
SELECT
Rn = ROW_NUMBER() OVER(ORDER BY Val),
Val
FROM CTE c
GROUP BY Val
HAVING COUNT(Val) > 1
)
,NotMatch AS(
SELECT
Rn = ROW_NUMBER() OVER(ORDER BY Val),
Val
FROM CTE c
GROUP BY Val
HAVING COUNT(Val) = 1
)
SELECT
Match = m.Val,
NotMatch= n.Val
FROM Match m
FULL JOIN NotMatch n
ON n.Rn = m.Rn
Try with EXCEPT, MINUS and INTERSECT Statements.
like this:
SELECT A FROM TABLE1 INTERSECT SELECT B FROM TABLE1;
You might want this:
SELECT DISTINCT
C.A as A
FROM
Table c
LEFT OUTER JOIN
Table d
ON
c.A=d.B
WHERE
d.ID IS NULL
Please Note that I use d.ID as an example because I don't see your schema. An alternate is to explicitly state all d.columns IS NULL in WHERE clause.
Your requirement is kind of - let's call it - interesting. Here is a way to solve it using pivot. Personally I would have chosen a different table structure and another way to select data:
Test data:
DECLARE #t table(A TINYINT, B TINYINT)
INSERT #t values
(1,5),(2,1),
(3,2),(4,1)
Query:
;WITH B AS
(
( SELECT A FROM #t
EXCEPT
SELECT B FROM #t)
UNION ALL
( SELECT B FROM #t
EXCEPT
SELECT A FROM #t)
), A AS
(
SELECT A val
FROM #t
INTERSECT
SELECT B
FROM #t
), combine as
(
SELECT val, 'A' col, row_number() over (order by (select 1)) rn FROM A
UNION ALL
SELECT A, 'B' col, row_number() over (order by (select 1)) rn
FROM B
)
SELECT [A], [B]
FROM combine
PIVOT (MAX(val) FOR [col] IN ([A], [B])) AS pvt
Result:
A B
1 3
2 4
NULL 5

How to remove null values and get row from values from table

Please help me with the task below. I have table a with four columns
col1,col2,col3 and col4. I want to retrieve from these columns, removing nulls.
So, if my table has
col1 | col2 | col3 | col4
-----+------+------+-----
A | B | NULL| NULL
C | D | NULL| NULL
NULL | NULL | E | F
NULL | NULL | G | H
I want result to be
col1 | col2 | col3 | col4
-----+------+------+-----
A | B | E | F
C | D | G | H
Here is a solution. I have used the analytic ROW_NUMBER() to synthesize a key for joining the rows. The join is full outer in order to cater for unequal assignments of nulls and values.
with cte as (select * from t23)
, a as ( select col1, row_number() over (order by col1) as rn
from cte
where col1 is not null )
, b as ( select col2, row_number() over (order by col2) as rn
from cte
where col2 is not null )
, c as ( select col3, row_number() over (order by col3) as rn
from cte
where col3 is not null )
, d as ( select col4, row_number() over (order by col4) as rn
from cte
where col4 is not null )
select a.col1
, b.col2
, c.col3
, d.col4
from a
full outer join b
on a.rn = b.rn
full outer join c
on a.rn = c.rn
full outer join d
on a.rn = d.rn
/
The SQL Fiddle is for Oracle, but this solution will work for any flavour of database which supports a ranking analytic function. The common table expression is optional, it just makes the other sub-queries easier to write.

Select Distinct From Table - Two Columns No Column Should Have Repetition

How do I a select against a table A for example which contains these records.
|Column1|Column2|
| A |F |
| A | G |
| B |G |
| B |H |
| C |H |
| D |H |
| E |I |
My expected result is:
|Column1 |Column2|
| A | F |
| B | G |
| C | H |
| E | I |
All columns should have a unique value in them.
What query statement can I use for this?
Thanks
Please try:
select
MIN(Column1) Column1,
Column2
from(
select
Column1,
MIN(Column2) Column2
from YourTable
group by Column1
)x group by Column2
order by 1
SQL Fiddle Demo
It didn't work for this scenario.
create table YourTable (Column1 varchar2(10),
Column2 varchar2(10));
insert into YourTable values ('B','F');
insert into YourTable values ('B','G');
insert into YourTable values ('B','H');
insert into YourTable values ('C','F');
insert into YourTable values ('C','G');
insert into YourTable values ('C','H');
insert into YourTable values ('D','F');
insert into YourTable values ('D','G');
insert into YourTable values ('D','H');
My expectation is
B F
C G
D H
but I only got
B F
Thanks a lot!
SELECT a.val, b.val FROM
(
SELECT val, rownum as rno
FROM
(
SELECT distinct column1 as val
FROM YourTable
)) a,
(
SELECT val, rownum as rno
FROM
(
SELECT distinct column2 as val
FROM YourTable
)) b
WHERE a.rno = b.rno
ORDER BY 1
/
VAL VAL_1
-----------
B F
C G
D H
OR
select column1 as val from YourTable
UNION
select column2 from YourTable
VAL
-----
B
C
D
F
G
H

Simple SQL Query -

I have data in a SQLServer table like this:
ID Name Year Value
-- ---- ---- -----
2 Ted 2013 2000
2 Ted 2012 1000
I need the view syntax to output this:
ID Name Yr1 Value1 Yr2 Value2
-- ---- --- ------ --- ------
2 Ted 2013 2000 2012 1000
No cursors if possible.
Any clues would be greatful.
In SQL Server there are several ways that you can get the result.
If you have a limited number of values, then you can easily hard-code the result. One way you can get the result would be using an aggregate function with a CASE expression:
select d.id,
d.name,
max(case when seq = 1 then year end) year1,
max(case when seq = 1 then value end) value1,
max(case when seq = 2 then year end) year2,
max(case when seq = 2 then value end) value2
from
(
select id, name, year, value,
row_number() over(partition by id order by year desc) seq
from yourtable
) d
group by d.id, d.name;
See SQL Fiddle with Demo. If you want to use the PIVOT function, then I would suggest first unpivoting the data in the year and value columns first. The process of unpivot converts the multiple columns into multiple rows. You can use the UNPIVOT function, but in my example I used CROSS APPLY with a UNION ALL query and the code is:
select t.id, t.name,
col = c.col+cast(seq as varchar(4)),
c.val
from
(
select id, name, year, value,
row_number() over(partition by id order by year desc) seq
from yourtable
) t
cross apply
(
select 'year', t.year union all
select 'value', t.value
) c (col, val)
See SQL Fiddle with Demo. This converts your multiple columns into a slightly different format with multiple rows:
| ID | NAME | COL | VAL |
| 2 | Ted | year1 | 2013 |
| 2 | Ted | value1 | 2000 |
| 2 | Ted | year2 | 2012 |
| 2 | Ted | value2 | 1000 |
You can then apply the PIVOT function on this to get your final desired result:
select id, name, year1, value1, year2, value2
from
(
select t.id, t.name,
col = c.col+cast(seq as varchar(4)),
c.val
from
(
select id, name, year, value,
row_number() over(partition by id order by year desc) seq
from yourtable
) t
cross apply
(
select 'year', t.year union all
select 'value', t.value
) c (col, val)
) d
pivot
(
max(val)
for col in (year1, value1, year2, value2)
) piv;
See SQL Fiddle with Demo. Finally if you have an unknown number of values that you want to transform from rows into columns, then you can use dynamic SQL inside a stored procedure:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(col+cast(seq as varchar(4)))
from
(
select row_number() over(partition by id order by year desc) seq
from yourtable
) d
cross apply
(
select 'year', 1 union all
select 'value', 2
) c (col, so)
group by seq, col, so
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT id, name,' + #cols + '
from
(
select t.id, t.name,
col = c.col+cast(seq as varchar(4)),
c.val
from
(
select id, name, year, value,
row_number() over(partition by id order by year desc) seq
from yourtable
) t
cross apply
(
select ''year'', t.year union all
select ''value'', t.value
) c (col, val)
) x
pivot
(
max(val)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo. All versions will give a result:
| ID | NAME | YEAR1 | VALUE1 | YEAR2 | VALUE2 |
| 2 | Ted | 2013 | 2000 | 2012 | 1000 |