Transforming rows having dynamic dates into columns - sql

Need to convert this:
DATE VALUE
18-DEC-15 2877544
17-DEC-15 2974276
16-DEC-15 4862020
into
18-DEC-15 17-DEC-15 16-DEC-15
2877544 2974276 4862020
The dates are updated everyday and I need to pick only the latest 3 dates and convert them into columns with the corresponding values below.
I tried using Pivots but I'm able to create the column headers dynamically.

Try this
WITH pivot_data AS (
select date, value from table)
SELECT *
FROM pivot_data
PIVOT (
max(value) --<-- pivot_clause
FOR table --<-- pivot_for_clause
);

A SQL query has well-defined column names, so for variable column names you need dynamic SQL. But, you can do what you want with fixed names:
select max(case when seqnum = 1 then value end) as MostRecentDay,
max(case when seqnum = 2 then value end) as SecondMostRecentDay,
max(case when seqnum = 3 then value end) as ThirdMostRecentDay
from (select t.*, dense_rank() over (order by date desc) as seqnum
from t
) t;
You could even add three columns specifying the date values:
select max(case when seqnum = 1 then value end) as MostRecentDay,
max(case when seqnum = 2 then value end) as SecondMostRecentDay,
max(case when seqnum = 3 then value end) as ThirdMostRecentDay,
max(case when seqnum = 1 then date end) as MostRecentDate,
max(case when seqnum = 2 then date end) as SecondMostRecentDate,
max(case when seqnum = 3 then date end) as ThirdMostRecentDate
from (select t.*, dense_rank() over (order by date desc) as seqnum
from t
) t;

Use Conditional Aggregate to pivot the data
select MAX(case when "DATE" = '18-DEC-15' then VALUE END) as '18-DEC-15',
MAX(case when "DATE" = '17-DEC-15' then VALUE END) as '17-DEC-15',
MAX(case when "DATE" = '16-DEC-15' then VALUE END) as '16-DEC-15'
from yourtable
Note : since dates are unknown, you need to use EXECUTE IMMEDIATE

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.

Keep the order of a multi string field using the pivot function?

I have a field "Remarks" that can have up to 10 codes pipe delimited. An example of the field results are below. I almost have the issue solved by using the Pivot function as shown below. The problem I cant seem to figure out is how to keep them in the correct order as in the remarks field. In the remark below 1|120|482|10 it returns in the rows in order 1 10 120 482 instead of 1 120 482 10. Any ideas?
SELECT
,Remarks
,[1] AS Remark4
,[2] AS Remark5
,[3] AS Remark6
,[4] AS Remark7
,[5] AS Remark8
,[6] AS Remark9
FROM (SELECT
,Remarks
,value
,dense_Rank() OVER(PARTITION BY Remarks ORDER BY value) as testnbr
from incident
CROSS APPLY STRING_SPLIT(Remarks, '|') AS BK
) as srctbl
PIVOT(
max(VALUE)
FOR testnbr IN([1],[2],[3],[4],[5],[6])
) as PVT
Remarks
1|120|170
1|120|375
1|120|482|10
I would just use conditional aggregation instead. But, the problem is that string_split() does not guarantee the ordering of the records. So, you can emulate this assuming there are no duplicate remarks :
select i.remarks, r.*
from incident i cross apply
(select max(case when seqnum = 1 then value end) as remark_1,
max(case when seqnum = 2 then value end) as remark_2,
max(case when seqnum = 3 then value end) as remark_3,
max(case when seqnum = 4 then value end) as remark_4,
max(case when seqnum = 5 then value end) as remark_5,
max(case when seqnum = 6 then value end) as remark_6
from (select value,
row_number() over (order by charindex('|' + value + '|', '|' + i.Remarks + '|') as seqnum
from string_split(i.Remarks, '|') s
) r

SQL count and combine

I'm setting up a query to change the data of a form, count data and format it. At this moment I've got a table with vertical data. The data is shown in the image below.
What I want to do is to create Group by on Number, after that count how many times a specific TypePak there is and split it to the right. As shown in the image on the right.
I've tried to do Pivot and it helped for a part of it, but that's not a good method. Then i've tried XML Path.
PIVOT
FROM dbo.des_ombouw
GROUP BY Number, typePak) src
pivot
(
max(Expr1)
for typePak in ([COLLI],[DOOS],[pallet],[Envelop])
) piv1
XML Path
select distinct Number, abc = STUFF((
select ',' + TypePak
from des_ombouw t1
where t1.Number = t2.Number
FOR XML PATH ('')),1,1,'')
from des_ombouw t2
In the image is what I want. There are more columns that has to be added, like weight of some package.
One of the problems too is that there are coming more columns, so this is not all!
Two steps of aggregation with row_number() may do what you want:
select d.number,
max(case when seqnum = 1 then cnt end) as cnt_1,
max(case when seqnum = 1 then typepak end) as typepak_1,
max(case when seqnum = 2 then cnt end) as cnt_2,
max(case when seqnum = 2 then typepak end) as typepak_2,
max(case when seqnum = 3 then cnt end) as cnt_3,
max(case when seqnum = 3 then typepak end) as typepak_3,
max(case when seqnum = 4 then cnt end) as cnt_4,
max(case when seqnum = 4 then typepak end) as typepak_4
from (select d.number, d.typepak, count(*) as cnt,
row_number() over (partition by d.number order by count(*) desc) as seqnum
from dbo.des_ombouw d
) d
group by d.number

Multiple rows into columns with column values group by columns in SQL Server

How to transform rows to column group by:
Desired result would be like this:
If you have a column that specifies the ordering, you can use conditional aggregation:
select max(case when columnname = 'SupplierGSTin' then value end) as SupplierGSTin,
max(case when columnname = 'DocumentNumber' then value end) as DocumentNumber,
max(case when columnname = 'SupplyType' then value end) as SupplyType
from (select t.*,
row_number() over (partition by columnname order by ?) as seqnum
from t
) t
group by rownum;
The ? is for the column that specifies the ordering.