Convert Table to another format in MSSQL - sql

I am facing a problem with MS-SQL in getting output from a table in a particular format.
Name | StringValue | Parent_ID
FieldName | TestHeader1 | 3
FieldValue | ValueForTestHeader1 | 3
FieldName | TestHeader2 | 6
FieldValue | ValueForTestHeader2 | 6
And I want to select data from this table as follows:
TestHeader1 | TestHeader2
ValueForTestHeader1 | ValueForTestHeader2
Any help would be highly appreciated!

use conditional aggregation
select max(case when parent_id=3 then stringvalue) as col1,
max(case when parent_id=6 then stringvalue) as col2
from tablename
group by parent_id

You can do conditional aggregation by using row_number() & dense_rank():
select max(case when seq1 = 1 then stringvalue end),
max(case when seq1 = 2 then stringvalue end)
from (select t.*,
dense_rank() over (order by parent_id) as seq1,
row_number() over (partition by parent_id order by stringvalue) seq2
from table t
) t
group by seq2;

Related

With some WHERE clause criteria, have SQL output go to next line

I am trying to write a query where I have some criteria where I pivot the results. However, due to output file constraints I am looking for the output to create a new line after the pivot exceeds X, even if the ID and such is otherwise the same.
What I am trying to do:
|--ID--|-Value-|
| 1 | val1 |
| 1 | val2 |
| 1 | val3 |
| 2 | val1 |
|--ID--|-Col1-|-Col2-|
| 1 | Val1| Val2|
| 1 | Val3| |
| 2 | Val1| |
SELECT *
FROM table
PIVOT(max(value) for field1 in (t1,t2)
as pvt
ORDER BY UNIQUE_ID
This is just a pivot example to pivot this particular column. However the output has a very strict number of column requirement so I'd be looking for any pivot beyond the 5th to "overflow" to the next row while retaining the unique id. I am looking at PIVOT but I dont think it will work here.
Is this even possible within the Snowflake platform or do I need to explore other options?
This requirement is purely presentation matter and in my opinion should not be performed at the database level. With that being said it is possible to achieve it by numbering rows in group and performing modulo division:
Samle data:
CREATE OR REPLACE TABLE tab
AS
SELECT 1 AS id, 'val1' AS value UNION
SELECT 1 AS id, 'val2' AS value UNION
SELECT 1 AS id, 'val3' AS value UNION
SELECT 2 AS id, 'val1' AS value;
Query:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY id ORDER BY value) - 1 AS rn
FROM tab
)
SELECT
id
,MAX(CASE WHEN rn % 2 = 0 THEN value END) AS col1
,MAX(CASE WHEN rn % 2 = 1 THEN value END) AS col2
FROM cte
GROUP BY id, FLOOR(rn / 2)
ORDER BY id, FLOOR(rn / 2);
Intermediate result:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY id ORDER BY value) - 1 AS rn
FROM tab
)
SELECT id,value, rn, FLOOR(rn / 2) AS row_index, rn % 2 AS column_index
FROM cte
ORDER BY ID, rn;
Generalized:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY id ORDER BY value) - 1 AS rn
FROM tab
)
SELECT
id
,MAX(CASE WHEN rn % N = 0 THEN value END) AS col1
,MAX(CASE WHEN rn % N = 1 THEN value END) AS col2
-- ....
,MAX(CASE WHEN rn % N = N-1 THEN value END) AS colN
FROM cte
GROUP BY id, FLOOR(rn / N)
ORDER BY id, FLOOR(rn / N);

Write a sql query to capture below information in a single row by using pivot

I have a table with three fields such as Name, Type and Amount
CREATE TABLE Customers
(
[Name] Varchar,
[Type] Varchar,
[Amount] int
);
INSERT INTO Customers (Name, Type, Amount)
VALUES ('Corporate', 'General', 300),
('Corporate', 'General', 400),
('Corporate', 'Specific', 4008);
And i want my output same like below
+-----------+---------+--------+---------+--------+----------+--------+
| Name | Type | Amount | Type | Amount | Type | Amount |
+-----------+---------+--------+---------+--------+----------+--------+
| Corporate | General | 300 | General | 400 | Specific | 4008 |
+-----------+---------+--------+---------+--------+----------+--------+
We might be able to use a ROW_NUMBER trick to pivot here:
WITH cte AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Amount) rn
FROM Customers
)
SELECT
Name,
MAX(CASE WHEN rn = 1 THEN Type END) AS Type1,
MAX(CASE WHEN rn = 1 THEN Amount END) AS Amount1,
MAX(CASE WHEN rn = 2 THEN Type END) AS Type2,
MAX(CASE WHEN rn = 2 THEN Amount END) AS Amount2,
MAX(CASE WHEN rn = 3 THEN Type END) AS Type3,
MAX(CASE WHEN rn = 3 THEN Amount END) AS Amount3
FROM cte
GROUP BY
Name;

Convert column value to row value

In SQL Server, I am trying to convert the from table 1 to table 2. From reading other answers from stack overflow, I can do some sort of row_number(). But the problem is I need do some inner join after the conversion because the following script use max() aggregate function, it kind force other fields from other tables to have some sort of aggregate function as well. So I was wondering if there is an alternative approach to solve this problem? Or if there is a way to handle this aggregate function when do join with another table.
select max(case when key = 'ab' then Value end) as ab,
max(case when key = 'cd' then Value end) as cd
from (select t.*,
row_number() over (partition by key order by Value) as seq
from table t
) t
group by seq;
table 1
table 2
You can try with this below script-
SELECT id,
MAX(CASE WHEN name = 'car1' THEN name END) car1,
MAX(CASE WHEN name = 'car2' THEN name END) car2,
MAX(CASE WHEN name = 'car3' THEN name END) car3
FROM your_table
GROUP BY id
You can go for PIVOT feature.
;WITH src as
(
SELECT *
FROM
(
VALUES
(1, 'Car1', 'nissan'),
(1, 'Car2', 'audi'),
(1, 'Car3', 'toyota')
) as t (id, name, value)
)
SELECT *
FROM src
PIVOT
(
max(VALUE) FOR NAME IN ([Car1], [Car2], [Car3])
) as pvt
+----+--------+------+--------+
| id | Car1 | Car2 | Car3 |
+----+--------+------+--------+
| 1 | nissan | audi | toyota |
+----+--------+------+--------+

Select SUM and column with max

I looking best or simplest way to SELECT type, user_with_max_value, SUM(value) GROUP BY type. Table look similar
type | user | value
type1 | 1 | 100
type1 | 2 | 200
type2 | 1 | 50
type2 | 2 | 10
And result look:
type1 | 2 | 300
type2 | 1 | 60
Use window functions:
select type, max(case when seqnum = 1 then user end), sum(value)
from (select t.*,
row_number() over (partition by type order by value desc) as seqnum
from t
) t
where seqnum = 1;
Some databases have functionality for an aggregation function that returns the first value. One method without a subquery using standard SQL is:
select distinct type,
first_value(user) over (partition by type order by value desc) as user,
sum(value) over (partition by type)
from t;
You can use window function :
select t.*
from (select t.type,
row_number() over (partition by type order by value desc) as seq,
sum(value) over (partition by type) as value
from table t
) t
where seq = 1;
Try below query.
It will help you.
SELECT type, max(user), SUM(value) from table1 GROUP BY type
use analytical functions
create table poo2
(
thetype varchar(5),
theuser int,
thevalue int
)
insert into poo2
select 'type1',1,100 union all
select 'type1',2,200 union all
select 'type2',1,50 union all
select 'type2',2,10
select thetype,theuser,mysum
from
(
select thetype ,theuser
,row_number() over (partition by thetype order by thevalue desc) r
,sum(thevalue) over (partition by thetype) mysum from poo2
) ilv
where r=1

TSQL Convert rows to columns

I have a query that returns some data that looks like this:
Description
----------
Thing1
Thing2
Thing3
Thing4
Thing5
Thing6
Thing7
I would like to make the data look like this:
Desc1 Desc2 Desc3
----- ----- -----
Thing1 Thing2 Thing3
Thing4 Thing5 Thing6
Thing7
Could someone provide an example on how to do this?
Thanks!
You stated the comments that the order of the data in the Desc columns does not matter.
If that is the case, then you can use the following which implement NTILE and row_number():
;with cte as
(
select description,
'desc'+cast(ntile(3) over(order by Description) as varchar(10)) col
from yt
)
select desc1, desc2, desc3
from
(
select description, col,
row_number() over(partition by col order by col) rn
from cte
) d
pivot
(
max(description)
for col in (desc1, desc2, desc3)
) piv;
See SQL Fiddle with Demo.
The NTILE function distributes the rows into separate groups. Once that is done, then apply a row_number() to give a unique number to each row while grouping.
This gives a result:
| DESC1 | DESC2 | DESC3 |
----------------------------
| Thing1 | Thing4 | Thing6 |
| Thing2 | Thing5 | Thing7 |
| Thing3 | (null) | (null) |
Another approach of doing it, if the order does matter, and skipping PIVOT function:
WITH CTE AS
(
SELECT
(ROW_NUMBER() OVER (ORDER BY [Description])+2) /3 AS RowID,
(ROW_NUMBER() OVER (ORDER BY [Description])+2) % 3 +1 AS ColID,
[Description]
FROM Table1
)
SELECT
MIN(CASE WHEN ColID = 1 THEN [Description] END) DESC1
,MIN(CASE WHEN ColID = 2 THEN [Description] END) DESC2
,MIN(CASE WHEN ColID = 3 THEN [Description] END) DESC3
FROM CTE
GROUP BY RowID
SQLFiddle DEMO
I used the base data from the sqlfiddle of #NenadZivkovic to provide a different solution
http://www.sqlfiddle.com/#!6/b676a/15
WITH Numbered AS
(
SELECT
ROW_NUMBER() OVER (ORDER BY Description) as rn,
(ROW_NUMBER() OVER (ORDER BY Description) - 1) % 3 as colid,
(ROW_NUMBER() OVER (ORDER BY Description) - 1) / 3 as line,
Description
FROM Table1
)
SELECT desc1.description as DESC1, desc2.description as DESC2, desc3.description as DESC3
FROM (SELECT line, description FROM Numbered WHERE colid=0) as desc1
LEFT JOIN
(SELECT line, description FROM Numbered WHERE colid=1) as desc2
ON (desc1.line = desc2.line)
LEFT JOIN
(SELECT line, description FROM Numbered WHERE colid=2) as desc3
ON (desc2.line = desc3.line)