How to Get row values as columns in SQL? - sql

I have a table Test with two columns.
Id Value
1 A
1 B
1 C
I want to get the result like below,
Id Value1 Value2 value3
1 A B C
How can I done this in SQL Server.

This is a pivot, but you don't have a column for the pivoting. row_number() can provide that. I usually use conditional aggregations for this.
select id,
max(case when seqnum = 1 then value end) as value1,
max(case when seqnum = 2 then value end) as value2,
max(case when seqnum = 3 then value end) as value3
from (select t.*,
row_number() over (partition by id order by (select null)) as seqnum
from t
) t
group by id;
Note that SQL tables represent unordered sets. So, there is no information about ordering and the values could be in any order. If a column does specify the ordering, then include that in the order by rather than select null.

Related

sql transformation - rows to column

i have been trying to solve this one image
my initial idea is like this
select name,
CASE
when count(name) = 1 then get first distinct value
when count(name) = 2 then get first distinct value
else get first distinct value
END as val1,
CASE
when count(name) = 1 then null
when count(name) = 2 then get second distinct value
else get second distinct value
END as val2,
CASE
when count(name) = 1 then null
when count(name) = 2 then null
else get third distinct value
END as val3
into desired_table
from source_table
group by name
is my attempt feasible? if so, how do i access the first, second and third distinct values?
use pivot . Your output table was incorrect. The correct form is available in db<>fiddle.
select name,x as value1,y as value2,z as value3
from
(
select *
from t1
) as SourceTable
pivot
(
max(value) for value in(x,y,z)
) as PivotTable
demo in db<>fiddle
You can use conditional aggregation along with row_number():
select name,
max(case when seqnum = 1 then value end) as value_1,
max(case when seqnum = 2 then value end) as value_2,
max(case when seqnum = 3 then value end) as value_3
into desired_table
from (select s.*,
row_number() over (partition by name order by value) as seqnum
from source_table s
) s
group by name;

Scenario is Transpose rows into columns

I have a table with two columns id and value where id integer datatype and value is decimal datatype
Output should be like that:
1,13.0264757,77.6361745
2,13.0276974,77.6327644
I use pivot operator but it is not working properly. Below query is my workout
select 1, 2, 3
from (
select id, value
from sampletest
) as srctable
pivot
(
sum(value)
for id in ([1],[2],[3])
) as pivttabl
SQL tables represent unordered sets. You can get values onto the rows using conditional aggregation. For instance, for two rows:
select min(case when column_id = 1 then value end),
min(case when column_id = 2 then value end),
min(case when column_id = 3 then value end)
from t
union all
select max(case when column_id = 1 then value end),
max(case when column_id = 2 then value end),
max(case when column_id = 3 then value end) ;
Note: This is not the results that you specify in your question.
If you have an ordering column, you can express what you want as:
select min(case when column_id = 1 then value end),
min(case when column_id = 2 then value end),
min(case when column_id = 3 then value end)
from (select t.*,
row_number() over (partition by column_id order by <ordering column>) as seqnum
from t
) t
group by seqnum;
If you don't have an ordering column of some sort, then you cannot reliably do what you want. Instead, you should fix your data model so the data has the information you need. This is usually handled by having an identity column; such a column is ordered by the "insert-order" of the rows into the table.

SQL create new column based on number of instances in different column

I want to create a new columns based on values in another column.
I have SQL database with below table:
col1 col2
2 H
2 H1
3 J
3 J1
3 J2
I try to transpose into the following:
col1 col2 col_new1 col_new2
2 H H1
3 J J1 J2
I use SQL report so can not define any variables or functions. Is there any CASE combination I could use?
This is slightly trickier than a simple pivot. Assuming you have at most three columns to pivot, you can do:
select col1,
max(case when seqnum = 1 then col2 end) as col2,
max(case when seqnum = 2 then col2 end) as col2_new1
max(case when seqnum = 3 then col2 end) as col2_new2
from (select t.*, row_number() over (partition by col1 order by col2) as seqnum
from t
) t
group by col1;
If you don't know the number of columns you want in the result set, then you cannot use a simple select. You need to use dynamic SQL.

SQL - sort of SUM with varchar

have a (weird) table looking like this
ID Version Value1 Value2 Value3
1 1 Shaft
1 2 steel xy
2 1 Knife somethins
2 3 Super
Want to merge, need to have this result, by using Value from the highest Version, that has content:
ID Value1 Value2 Value3
1 Shaft steel xy
2 Super Knife somethin
as far as I know Group using Max(Version) would bring the NULL values of highest Version row.
something like SUM?
Second try... There are probably shorter and nicer solutions, but it should work:
with
v1 as
(
select w1.id, w1.value1 from weird w1
where w1.value1 is not null
and w1.version=(select max(w11.version) from weird w11 where w11.id=w1.id and w11.value1 is not null)
),
v2 as
(
select w2.id, w2.value2 from weird w2
where w2.value2 is not null
and w2.version=(select max(w22.version) from weird w22 where w22.id=w2.id and w22.value2 is not null)
),
v3 as
(
select w3.id, w3.value3 from weird w3
where w3.value3 is not null
and w3.version=(select max(w33.version) from weird w33 where w33.id=w3.id and w33.value3 is not null)
)
select v1.id, v1.value1, v2.value2, v3.value3
from v1, v2, v3
where v1.id=v2.id and v1.id=v3.id;
We can use UNPIVOT and PIVOT creatively to construct the data you want:
declare #t table (ID int not null, Version int not null, Value1 varchar(20) null,
Value2 varchar(20) null, Value3 varchar(20) null)
insert into #t(ID,Version,Value1,Value2,Value3) values
(1,1,'Shaft',null,null),
(1,2,null,'steel','xy'),
(2,1,null,'Knife','somethins'),
(2,3,'Super',null,null)
;With Numberable as (
select *,ROW_NUMBER() OVER (PARTITION BY ID,Val ORDER BY Version desc) rn
from #t t
unpivot (tdata for Val in (Value1,Value2,Value3)) u
), Selected as (
select ID,tdata,Val
from Numberable where rn = 1
)
select
*
from Selected s
pivot (MAX(tdata) for Val in (Value1,Value2,Value3)) u
The UNPIVOT automatically removes the NULLs. The ROW_NUMBER() identifies the values we want to keep. The Selected CTE hides the columns we no longer need so that the PIVOT creates the final result we want:
ID Value1 Value2 Value3
----------- -------------------- -------------------- --------------------
1 Shaft steel xy
2 Super Knife somethins
(I'm using MAX in the pivot but that's just to satisfy the optimizer. Because we've only selected one row for each ID, Val combination, we know that at most one value will be selected to appear in a final position in the grid formed by the pivot)
The above does make the assumption that Value1,Value2 and Value3 all have the same, or at least compatible, data types.
You can rank the values with row_number. The following query first builds such ranks. rn1 is built per id and value1 is null/not null in the descending order of the version. So per ID we get #1 for the last null value and the last filled value. Later we use rn1 = 1 to get the maximum of the two, which is the last filled value. Same for rn2/value2 and rn3/value3.
select
id,
min(case when rn1 = 1 then value1 end) as value1,
min(case when rn2 = 1 then value2 end) as value2,
min(case when rn3 = 1 then value3 end) as value3
from
(
select
id, value1, value2, value3,
row_number() over (partition by id, case when value1 is null then 0 else 1 end order by version desc) as rn1,
row_number() over (partition by id, case when value2 is null then 0 else 1 end order by version desc) as rn2,
row_number() over (partition by id, case when value3 is null then 0 else 1 end order by version desc) as rn3
from mytable
) ranked
group by id
order by id;
Used CASE WHEN to SELECT max(version) where value is not null and not blank and then joinedwith the original table on those versions. You can see it in action in link provided below the query
Use this query.
Select distinct a.*, b.value1, c.value2, d.value3
from
(
Select id, max(case when (value1 is not null and value1 <> ' ') then version else 0 end) as ver1,
max(case when (value2 is not null and value2 <> ' ') then version else 0 end) as ver2,
max(case when (value3 is not null and value3 <> ' ') then version else 0 end) as ver3
from
your_table
group by id
) a
inner join
your_table b,
your_table c,
your_table d
where (a.ver1=b.version and a.id=b.id)
and (a.ver2=c.version and a.id=c.id)
and (a.ver3=d.version and a.id=d.id)
See it in action here at this link

SQL query to return history as flat format

Looking for help with an SQL query to turn a history table into flat file format with up to 5 instances of results on table B. I have only shown 2 instances in the results. For a bonus point can these be sorted by EFF_DATE ascending?!
My query so far is
SELECT a.REFNO, a.M_NAME, b.EFF_DATE, b.VAL
FROM TABLEA a INNER JOIN TABLEB b ON (a.REFNO=b.REFNO)
WHERE a.REFNO = '1'
This is fine for returning results once per row, but how do I modify so up to 5 EFF_DATE and VAL instances are repeated on one row. The dates can be any date and ideally would like them sorted ascending left to right. Only those rows on TABLEB where Val > 0 should be included.
If you know the number of columns you want in the history, then you can use conditional aggregation or pivot. The challenge is not having a column for the pivot.
You can easily generate one, though, using ROW_NUMBER():
SELECT a.REFNO, a.M_NAME,
MAX(CASE WHEN seqnum = 1 THEN b.EFF_DATE END) as EFF_DATE_1,
MAX(CASE WHEN seqnum = 1 THEN b.VAL END) as VAL_1,
MAX(CASE WHEN seqnum = 2 THEN b.EFF_DATE END) as EFF_DATE_2,
MAX(CASE WHEN seqnum = 2 THEN b.VAL END) as VAL_2,
MAX(CASE WHEN seqnum = 3 THEN b.EFF_DATE END) as EFF_DATE_3,
MAX(CASE WHEN seqnum = 3 THEN b.VAL END) as VAL_3
FROM TABLEA a INNER JOIN
(SELECT b.*,
ROW_NUMBER() OVER (PARTITION BY REFNO ORDER BY EFF_DATE) as seqnum
FROM TABLEB b
) b
ON a.REFNO = b.REFNO
WHERE a.REFNO = '1'
GROUP BY a.REFNO, a.M_NAME;
If you don't know the number of columns in the output, then you will need dynamic SQL or to do the formatting at the application layer.