Divide N rows to N columns - sql

I have a result set which provide me 2 columns named Sequence and CorrectAns and it contains N rows(100 rows right now to be specific).
Now what I want is to divide these 100 rows to N columns(right now into 4 columns).
So, how to do that? Any help would be appreciated.
This is the result that i am getting. Now what I want is something like this:
Seq ColA Seq ColB Seq ColC Seq ColD
1 C 4 A 7 C 10 D
2 A 5 C 8 A 11 C
3 A 6 A 9 C 12 A
and so on.
Hope this helps

What you want is to pivot your data. Aside from the PIVOT command, one way to do that is to use conditional aggregation:
SQL Fiddle
;WITH Cte AS(
SELECT *,
grp = (ROW_NUMBER() OVER(ORDER BY Seq) -1) %
(SELECT CEILING(COUNT(*) / (4 * 1.0)) FROM tbl)
FROM tbl
),
CteFinal AS(
SELECT *,
rn = ROW_NUMBER() OVER(PARTITION BY grp ORDER BY Seq)
FROM Cte
)
SELECT
SeqA = MAX(CASE WHEN rn = 1 THEN Seq END),
ColA = MAX(CASE WHEN rn = 1 THEN CorrectAns END),
SeqB = MAX(CASE WHEN rn = 2 THEN Seq END),
ColB = MAX(CASE WHEN rn = 2 THEN CorrectAns END),
SeqC = MAX(CASE WHEN rn = 3 THEN Seq END),
ColC = MAX(CASE WHEN rn = 3 THEN CorrectAns END),
SeqD = MAX(CASE WHEN rn = 4 THEN Seq END),
ColD = MAX(CASE WHEN rn = 4 THEN CorrectAns END)
FROM CteFinal
GROUP BY grp

use the following query,
SELECT *
FROM (
SELECT
Seq, CorrectAns,
gro
FROM your_table
) as t
PIVOT
(
SUM(gro)
FOR CorrectAns IN (A,B,C,D....)
)AS pvt

If i understood what you said clearly, you can put your result set in an Array.
and then use this SQL QUERY
ALTER TABLE table_name
ADD column_name datatype
Example :
ALTER TABLE customer ADD name VARCHAR(Max);
You can specified a loop from the 0 to size of the Array and put that query inside the loop.
Edit :
Ok, I think it should be something like this;
DECLARE #cnt INT = 0;
DECLARE #str = "";
WHILE #cnt < 100000
BEGIN
SET #cnt = #cnt + 1;
SET #str='yourRowName';
ALTER TABLE yourTableName
ADD str datatype
END;
Take a look at this.
http://www.techonthenet.com/sql_server/loops/for_loop.php

Related

SQL Function for updating column with values

Those who have helped me before, i tend to use SAS9.4 a lot for my day to day work, however there are times when i need to use SQL Server
There is a output table i have with 2 variables (attached output.csv)
output table
ID, GROUP, DATE
The table has 830 rows:
330 have a "C" group
150 have a "A" group
50 have a "B" group
the remaining 300 have group as "TEMP"
within SQL i do not now how to programatically work out the total volume of A+B+C. The aim is to update "TEMP" column to ensure there is an Equal amount of "A" and "B" totalling 250 of each (the remainder of the total count)
so the table totals
330 have a "C" group
250 have a "A" group
250 have a "B" group
You want to proportion the "temp" to get equal amounts of "A" and "B".
So, the idea is to count up everything in A, B, and Temp and divide by 2. That is the final group size. Then you can use arithmetic to allocate the rows in Temp to the two groups:
select t.*,
(case when seqnum + a_cnt <= final_group_size then 'A' else 'B' end) as allocated_group
from (select t.*, row_number() over (order by newid()) as seqnum
from t
where group = 'Temp'
) t cross join
(select (cnt_a + cnt_b + cnt_temp) / 2 as final_group_size,
g.*
from (select sum(case when group = 'A' then 1 else 0 end) as cnt_a,
sum(case when group = 'B' then 1 else 0 end) as cnt_b,
sum(case when group = 'Temp' then 1 else 0 end) as cnt_temp
from t
) g
) g
SQL Server makes it easy to put this into an update:
with toupdate as (
select t.*,
(case when seqnum + a_cnt <= final_group_size then 'A' else 'B' end) as allocated_group
from (select t.*, row_number() over (order by newid()) as seqnum
from t
where group = 'Temp'
) t cross join
(select (cnt_a + cnt_b + cnt_temp) / 2 as final_group_size,
g.*
from (select sum(case when group = 'A' then 1 else 0 end) as cnt_a,
sum(case when group = 'B' then 1 else 0 end) as cnt_b,
sum(case when group = 'Temp' then 1 else 0 end) as cnt_temp
from t
) g
) g
)
update toupdate
set group = allocated_group;
I'd go with a top 250 update style approach
update top (250) [TableName] set Group = 'A' where exists (Select * from [TableName] t2 where t2.id = [TableName].id order by newid()) and Group = 'Temp'
update top (250) [TableName] set Group = 'B' where exists (Select * from [TableName] t2 where t2.id = [TableName].id order by newid()) and Group = 'Temp'

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;

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

Selecting 3 rows into 3 columns in sql server

I am trying to select the 3 rows into 3 columns, but i get NULL values.
Here is my code so far:
SELECT * FROM
(
SELECT t_k
FROM m_t_k
WHERE p_id = 5 and t_k_id in (1,2,7)
) src
PIVOT(
MAX()
for t_k in ([1],[2],[3])
) piv
this is the result of the query without the PIVOT
and i want those rows to be on 3 columns
You could use ROW_NUMBER and a Cross Tab to achieve this. This is a bit of a guess, based on the query and image we have though, so it is untested:
SELECT MAX(CASE WHEN RN = 1 THEN sq.term_key END) AS term_key1,
MAX(CASE WHEN RN = 2 THEN sq.term_key END) AS term_key2,
MAX(CASE WHEN RN = 3 THEN sq.term_key END) AS term_key3
FROM (SELECT term_key,
ROW_NUMBER() OVER (ORDER BY term_key) AS RN
FROM mpos_term_key
WHERE profile_id = 5
AND term_keys_type_id IN (1, 2, 7)) sq;

SQL Row_Number() increase only when the value = 1 for a specific column

I am having some trouble generating row_number() in my SQL query as my expectation. I have this following output of my query-
Now, I want to add row number for all rows where row number will only increase when the value in C1 is = 1. Required output as below-
Any help will be appreciated. TIA
Table Variable:
DECLARE #Table AS TABLE (C1 INT)
INSERT INTO #Table VALUES (1),(4),(1),(1),(4),(1),(3),(4)
SQL 2008 Version
;WITH cteSimulateAnOriginalIdentityKey AS (
SELECT
C1
,OriginalOrder = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM
#Table
)
, cteC1RowNumber AS (
SELECT
*
,C1RowNumber = ROW_NUMBER() OVER (PARTITION BY C1 ORDER BY OriginalOrder)
FROM
cteSimulateAnOriginalIdentityKey
)
SELECT
C1
,RN = ISNULL((SELECT MAX(C1RowNumber) FROM cteC1RowNumber r2 WHERE r2.C1 = 1 AND r2.OriginalOrder <= r1.OriginalOrder),1)
FROM
cteC1RowNumber r1
ORDER BY
OriginalOrder
SQL 2012+ version
;WITH cteSimulateAnOriginalIdentityKey AS (
SELECT
C1
,OriginalOrder = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM
#Table
)
, cteC1RowNumber AS (
SELECT
*
,C1RowNumber = ROW_NUMBER() OVER (PARTITION BY C1 ORDER BY OriginalOrder)
FROM
cteSimulateAnOriginalIdentityKey
)
SELECT
C1
,RN = ISNULL(MAX(CASE WHEN C1 = 1 THEN C1RowNumber END) OVER (ORDER BY OriginalOrder),1)
FROM
cteC1RowNumber
ORDER BY
OriginalOrder
RESULT:
C1 RN
1 1
4 1
1 2
1 3
4 3
1 4
3 4
4 4
If you in fact have another column by which to maintain the desired original order you don't need the first cte which is simply simulating that column
Try this:
SELECT C1,
ROW_NUMBER() OVER (PARTITION BY C1 ORDER BY (SELECT 100)) RN
FROM TableNAme
I presume you have another column(s) in your query by which you determine the order of rows; without such a criteria, your whole question is pointless.
The query below will work on SQL Server 2012 or later versions:
declare #Table table (
Id int identity(1,1) not null,
C1 int
);
insert into #Table(C1) values (1),(4),(1),(1),(4),(1),(3),(4);
select t.C1,
sum(case t.C1 when 1 then 1 else 0 end) over(order by t.Id) as [RN]
from #Table t;