Structure the Data horizontally in Sql - sql

Hi I have a query which returns data as below
select
n.Key, np.value
from
Test1 np
join Test2 n on n.Key = np.Key
where
n.NodeKey = 10000002 && np.pKey in (4,6,7,10,12)
which returns data as below
Key value
-------- ------
10000002 2
10000002 0
10000002 2
10000002 True
10000002 1
Test2 is look up Table as below
Key PKey Value
---------------------------------------
10000002 4 2
10000002 6 0
10000002 7 2
10000002 10 True
10000002 12 1
Wanted to change the query so that it should return data as below
NodeKey Value1 Value2 Value3 Value4 Value5
--------------------------------------------------
10000002 2 0 2 True 1
Can you please help me with this.

You may use pivot clause as :
with t as
(
select i.* from Test2 i
)
select [Key] as 'NodeKey',
[4] as 'Value1',
[6] as 'Value2',
[7] as 'Value3',
[10] as 'Value4',
[12] as 'Value5'
from t
pivot
(
max(Value) for PKey in ([4], [6], [7], [10], [12])
) q;
NodeKey Value1 Value2 Value3 Value4 Value5
-------- ------ ------ ------ ------ -------
10000002 2 0 2 True 1
Rextester Demo

You can try using sql-server pivot For structuring data horizontally.
Try below code..
Add another column using row_number() function and Store whole result in temp table
select
n.Key, np.value,
'Value'+convert(varchar(2),ROW_NUMBER() over (partition by [key] order by [key])) as tmpCol
into #tempTable --store result in tmp table
from
Test1 np
join Test2 n on n.Key = np.Key
where
n.NodeKey = 10000002 && np.pKey in (4,6,7,10,12)
then use below pivot code.
select *
from
(
select [key], value,tmpCol
from #tempTable
) src
pivot
(
max(value)
for tmpCol in (value1,value2,value3,value4,value5)
) piv;

Related

Sql Group by Value1 having count(*) > 1 but with different value 2

Given an SQL table like this
id value1 value2
---------------
1 1 1
2 1 1
3 1 1
4 2 1
5 2 2
6 3 1
I want to find all the value1's that have duplicate value1 (i.e using group by having count(*)>1) but only if they have different values for value2
So in this example I just want to return 2
Im using Postgres
If I understand correctly, this is group by with a having clause:
select value1
from t
group by value1
having min(value2) <> max(value2)
use
select * from ( select * , ROW_NUMBER() OVER(PARTITION BY Value1 ORDER BY Value1 , Value2 ASC) AS RowValue1, ROW_NUMBER() OVER(PARTITION BY Value1 , Value2 ORDER BY Value1 , Value2 ASC) AS RowValue2 from Table_1 ) As TableTmp where TableTmp.RowValue1 <> TableTmp.RowValue2
Or
select * from Table_1 where value1 in (select value1 from Table_1 group by value1 having min(value2) <> max(value2) )

How to I convert this column to row format ?

I can use Pivot but my table here has only 2 columns so I don't know how to go about with it. A class has maximum of 5 UserIDs so I want to have a ClassID and associated 5 user names.
UserID ClassID
RK980 5
LO567 5
YY667 5
RT223 5
LT987 3
What I need is :
ClassID User1 User2 User3 User4 User5
5 RK980 LO567 YY667 RT223 NULL
3 LT987 NULL NULL NULL NULL
Thank you !
You can use row_number(). I would then tend to go for conditional aggregation rather than pivot:
select classid,
max(case when seqnum = 1 then userid end) as user1,
max(case when seqnum = 2 then userid end) as user2,
max(case when seqnum = 3 then userid end) as user3,
max(case when seqnum = 4 then userid end) as user4,
max(case when seqnum = 5 then userid end) as user5
from (select t.*, row_number() over (partition by classid order by userid) as seqnum
from t
) t
group by classid;
you can use pivot with row_number
DECLARE #MyTable TABLE (UserID VARCHAR(10), ClassID INT)
INSERT INTO #MyTable VALUES
('RK980', 5 ),
('LO567', 5 ),
('YY667', 5 ),
('RT223', 5 ),
('LT987', 3 )
SELECT ClassID, [1] User1, [2] User2, [3] User3, [4] User4, [5] User5 FROM
(SELECT * ,
ROW_NUMBER() OVER(PARTITION BY ClassID ORDER BY UserID ) AS RN
FROM #MyTable ) SRC
PIVOT(MAX(UserID) FOR RN IN ([1], [2], [3], [4], [5])) PVT
Result:
ClassID User1 User2 User3 User4 User5
----------- ---------- ---------- ---------- ---------- ----------
3 LT987 NULL NULL NULL NULL
5 LO567 RK980 RT223 YY667 NULL

SQL Server convert a table column values to names and assign 0 to the new columns if no value for a column

I would like to transform a table from rows to columns in SQL Server.
Given table1:
id value1 value2
1 name1 9
1 name1 26
1 name1 15
2 name2 20
2 name2 18
2 name2 61
I need a table like:
id name1 name2
1 9 0
1 26 0
1 15 0
2 0 20
2 0 18
2 0 61
Can pivot help here? An efficient way is preferred to do the convert because the table is large.
I have tried:
select
id, name1, name2
from
(select
id, value1, value2
from table1) d
pivot
(
max(value2)
for value1 in (name1, name2)
) piv;
But, it cannot provide all rows for same ID to combine with 0s.
Thanks
The 'secret' is to add a column to give uniqueness to each row within your 'nameX' groups. I've used ROW_NUMBER. Although PIVOT requires an aggregate, with our 'faked uniqueness' MAX, MIN etc will suffice. The final piece is to replace any NULLs with 0 in the outer select.
(BTW, we're on 2014 so I can't test this on 2008 - apologies)
SELECT * INTO #Demo FROM (VALUES
(1,'name1',9),
(1,'name1',26),
(1,'name1',15),
(2,'name2',20),
(2,'name2',18),
(2,'name2',61)) A (Id,Value1,Value2)
SELECT
Id
,ISNULL(Name1, 0) Name1
,ISNULL(Name2, 0) Name2
FROM
( SELECT
ROW_NUMBER() OVER ( PARTITION BY Id ORDER BY Id ) rn
,Id
,Value1
,Value2
FROM
#Demo ) A
PIVOT ( MAX(Value2) FOR Value1 IN ( [Name1], [Name2] ) ) AS P;
Id Name1 Name2
----------- ----------- -----------
1 9 0
1 26 0
1 15 0
2 0 20
2 0 18
2 0 61
you can do case based aggregation with group by
SQL Fiddle
select id,
max(case when value1 ='name1' then value2 else 0 end) as name1,
max(case when value1 ='name2' then value2 else 0 end) as name2
from Table1
group by id, value1, value2

Teradata SQL pivot multiple results and eliminate duplicate values

I have something like this:
ID Result
1 value1
2 value1
2 value2
3 value1
3 value1
4 value1
4 value2
4 value3
Notice that ID 3 has the same result appearing in two rows.
Thanks to bluefeet (teradata sql pivot multiple occurrences into additional columns), I was able to produce something like this:
ID Result1 Result2 Result3
1 value1
2 value1 value2
3 value1
4 value1 value2 value3
I'm getting what I want, but because ID 3 has multiple results, they are counted as 2 and then included in the second column, which is for those results that return 2 occurrences for one ID.
What I would like it do is simply return the first occurrence of the duplicate ID 3 result in the Result1 column, like this:
ID Result1 Result2 Result3
1 value1
2 value1 value2
3 value1
4 value1 value2 value3
How can I eliminate that duplicate result and prevent it from counting?
TD14.10 finally added DENSE_RANK (which could be used instead of ROW_NUMBER in bluefeet's query), but before you have to add some kind of DISTINCT processing, e.g.:
SELECT id,
MAX(CASE WHEN seq =1 THEN res END) result1,
MAX(CASE WHEN seq =2 THEN res END) result2,
MAX(CASE WHEN seq =3 THEN res END) result3
FROM
(
SELECT id, res, ROW_NUMBER() OVER(PARTITION BY id ORDER BY res) seq
FROM
(
SELECT DISTINCT id, res
FROM yourtable
) d
) d
GROUP BY id
ORDER BY id;

Partial pivot without pivot operator

I am looking for a query to partially pivot a table without using the PIVOT operator (old ms-sql server).
the table:
id-------item---------rank1---------rank2
231------it1--------- 1 ----------- 1
231------it2-------- 1 ----------- 2
231------it3--------- 1 ----------- 3
154------it4--------- 3 ----------- 4
154------it2--------- 1 ----------- 2
155------it2--------- 1 ----------- 2
156------it3 -------- 2 ----------- 2
156------it1 -------- 1 ----------- 1
expected result:
id---------item1----item2----item3---item*...
231 -------it1------it2---------it3
154--------it2------it4
155--------it2
156--------it1------it3
order by rank1 and rank2
I searched on google but the solution I found was too complicated to apply.
In SQL Server, you could use row_number to assign a row number for each id group. Then you can use the max(case(... trick to pivot:
select id
, max(case when rn = 1 then item end) as item1
, max(case when rn = 2 then item end) as item2
, max(case when rn = 3 then item end) as item3
from (
select row_number() over (partition by id
order by rank1, rank2) as rn
, *
from YourTable
) as SubQueryAlias
group by
id
There is no general solution for N items without using dynamic SQL.