How to convert multiple columns into a single row with row number? - sql

I'm trying to figure out a way to convert
[Column1],[Column2],[Column3],[Column4],[Column5] into a single column [Type]. I also want it to have row number. So an example of how I would want it to look like. ALso, what if I just want column with data to output? Like Column1 and Column2 both have values but column3, 4, and 5 don't. In this case, I just want 1 and 2 to show on my resultset.
Now:
[ID1]-[Column1],[Column2],[Column3],[Column4],[Column5]
[ID2]-[Column1],[Column2],[Column3],[Column4],[Column5]
Desire:
[ID1]-[Column1],[Row1]
[ID1]-[Column2],[Row2]
[ID1]-[Column3],[Row3]
[ID1]-[Column4],[Row4]
[ID1]-[Column5],[Row5]
[ID2]-[Column1],[Row1]
[ID2]-[Column2],[Row2]
Etc......
Thank you!

Try some thing like this but this is may not reliable solution but get work done first
SELECT Col,Row_NUMBER() OVER(ORDER BY [ID]) RowNo
FROM (
SELECT [ID],CAST([ID] AS VARCHAR(30))+'-'+[COLUMN1] as Col
FROM TableName
UNION ALL
SELECT [ID],CAST([ID] AS VARCHAR(30))+'-'+[COLUMN2] as Col
FROM TableName
UNION ALL
SELECT [ID],CAST([ID] AS VARCHAR(30))+'-'+[COLUMN3] as Col
FROM TableName
...Like wise for other columns
)M
ORDER BY [ID]

one way to unpivot a table is by using Cross/Outer apply and Table Value Constructors.
--sample data
WITH cte AS (
SELECT *
FROM (VALUES (1, 'col1', 'col2', 'col3', 'col4', 'col5'),
(2, 'col1', 'col2', 'col3', 'col4', 'col5'))
t(id, column1,column2,column3,column4,column5)
)
--query
SELECT cte.id,
t.*
FROM cte
OUTER APPLY (VALUES(column1, 1),(column2, 2),(column3, 3),(column4, 4),(column5, 5)) t([type],[rownum])

You can use UNPIVOT to reverse columns to rows:
;WITH YourTable AS (
SELECT *
FROM (VALUES
('ID1','Column11','Column12','Column13','Column14','Column15'),
('ID2','Column21','Column22','Column23','Column24','Column25')
) as t([ID],[Column1],[Column2],[Column3],[Column4],[Column5])
)
SELECT *
FROM (
SELECT [Column1] as [Row1],
[Column2] as [Row2],
[Column3] as [Row3],
[Column4] as [Row4],
[Column5] as [Row5],
[ID]
FROM YourTable
) t
UNPIVOT (
[Type] FOR [Column] IN ([Row1],[Row2],[Row3],[Row4],[Row5])
) as unp
Output:
ID Type Column
ID1 Column11 Row1
ID1 Column12 Row2
ID1 Column13 Row3
ID1 Column14 Row4
ID1 Column15 Row5
ID2 Column21 Row1
ID2 Column22 Row2
ID2 Column23 Row3
ID2 Column24 Row4
ID2 Column25 Row5

Related

How to convert a single row table into columns?

I have a single row query returning data in this format:
Col1 Col2 Col3 Col4
-----------------------------
1425 3454 2345 3243
I want it to display it in this format:
Col1 | 1425
Col2 | 3454
Col3 | 2345
Col4 | 3243
How can I do it?
I am avoiding to use UNION method since the above table is extracted from a query and for each <table_name> I would have to paste the table query which will make the process slow.
If the number of fields per table is always constant, then it might work like this.
DECLARE #Table TABLE(
[Col1] int,
[Col2] int,
[Col3] int,
[Col4] int
)
INSERT INTO #Table VALUES(1425, 3454, 2345, 3243); -- some Test data
SELECT * FROM #Table; -- row
SELECT
p.[Columns],
p.[Value]
FROM (
SELECT
[Col1],
[Col2],
[Col3],
[Col4]
FROM #Table
) x
UNPIVOT(
[Value] FOR [Columns] IN ([Col1],[Col2],[Col3],[Col4]) --
) AS P;
You can cross join your query with the column names in order to show the column values in separate rows:
select
columns.col,
case columns.col
when 'Col1' then q.col1
when 'Col2' then q.col2
when 'Col3' then q.col3
when 'Col4' then q.col4
end as value
from ( <your query here> ) q
cross join ( values ('Col1'), ('Col2'), ('Col3'), ('Col4') ) as columns(col);

SQL command to break up a column into additional columns

I am trying to take one column in my table that has multiple values (up to 10) delimited by a "pipe" "|" in it and add the delimited values into additional columns in the table. Note (running on SQL SVR 2014).
Table ...
Col1 Col2 Col3
1 Tom 12345678|87654321|11111111|22222222|..... up to 10
2 Joe 14563467
3 Zac 12345678|87654321
I need the results of SQL to produce
Col1 Col2 Col3 Col4 Col5 Col6 Col7 Col8 Col9 ....
1 Tom 12345678 87654321 11111111 22222222
2 Joe 14563467
3 Zac 12345678 87654321
Any help is appreciated!
You can first normalize your data using the new STRING_SPLIT function into a derived table with the split columns stretched downward. Using that table you can PIVOT out based on Col1 to create the 5 columns basically pulling the data back up that was previously split down. Next, use that data as the source for you update back to the source table.
If you are not on SQL Server 2016 then you will need to replace STRING_SPLIT with an delimited string parser Table Value Function .
DECLARE #T TABLE(Col1 INT, Col2 NVARCHAR(50), Col3 NVARCHAR(50), Col4 NVARCHAR(50), Col5 NVARCHAR(50))
INSERT #T (COl1,Col2) VALUES (1,'12345678|87654321|11111111|22222222|')
INSERT #T (COl1,Col2) VALUES (2,'12345678')
INSERT #T (COl1,Col2) VALUES (3,'12345678|87654321|')
SELECT * FROM #T
;
WITH SplitData AS
(
SELECT
Col1,Col2 = S.Value,
RN = ROW_NUMBER()OVER( PARTITION BY Col1 ORDER BY (SELECT 1 AS X))
FROM
#T
CROSS APPLY STRING_SPLIT(Col2,'|') S
)
,UpdateData AS
(
SELECT
Col1, Col2=[1], Col3=[2], Col4=[3], Col5=[4]
FROM
(
SELECT Col1, Col2, RN FROM SplitData
) AS S
PIVOT(
MAX(Col2) FOR RN IN ([1], [2], [3], [4], [5])
) AS P
)
UPDATE L
SET L.Col1 = R.Col1, L.Col2=R.Col2, L.Col3=R.Col3, L.Col4=R.Col4, L.Col5 = R.Col5
FROM
#T L
INNER JOIN UpdateData R ON L.Col1 = R.Col1
SELECT * FROM #T
If u are sure max values count in Col3 is 10 u can use cross apply with split string on Col3 and select columns with splited value and row number partitioned by col1 and col2. Secound step is pivot this table by row
WITH SplitTable AS(
SELECT Col1
,Col2
,value
,ROW_NUMBER() OVER(PARTITION BY Col1, Col2 ORDER BY (SELECT NULL)) as rn
FROM YOUR_TABLE
CROSS APPLY STRING_SPLIT(Col3, '|') AS YT
)
SELECT Col1
,Col2
,[1]
,[2]
,[3]
,[4]
,[5]
,[6]
,[7]
,[8]
,[9]
,[10]
FROM SplitTable
PIVOT(
MAX(VALUE)
FOR RN IN([1],[2],[3],[4],[5],[6],[7],[8],[9],[10])
) as PVT

Not sure about the below scenario. Need a bit push. How can I solve below sql scenario

Input:
COL1 COL2
---------------
10 a
20 b
30 c
40 NULL
50 d
Desired output:
COL1 COL2
-----------------
10 a
20 a,b
30 a,b,c
40 a,b,c
50 a,b,c,d
Below is the solution I have tried so far. But this is not returning the desired output.
WITH CTE AS
(
SELECT
COL1,
LAG(COL2) OVER (ORDER BY COL1) AS prev_word,
COL2
FROM
dbo.Scenario
), CTE_A AS
(
SELECT
COL1, COL2, prev_word,
CONCAT(ISNULL(Prev_word, ''), ' ', ISNULL(COL2, '')) AS Con_Word
FROM
CTE
)
SELECT *
FROM CTE_A
One possible solution is the following statement. I assume, that the values in the COL1 column define the order, that is needed for the aggregation.
Table:
CREATE TABLE Data (
COL1 int,
COL2 varchar(1)
)
INSERT INTO Data (COL1, COL2)
VALUES
(10, 'a'),
(20, 'b'),
(30, 'c'),
(40, NULL),
(50, 'd')
Statement for SQL Server 2012:
SELECT d.COL1, STUFF(a.COL2, 1, 1, '') AS COL2
FROM Data d
CROSS APPLY (
SELECT CONCAT(',', COL2)
FROM Data
WHERE COL1 <= d.COL1 AND COL2 IS NOT NULL
ORDER BY COL2
FOR XML PATH('')
) a (COL2)
ORDER BY d.COL1
Statement for SQL Server 2017+ (using STRING_AGG() for string aggregation):
SELECT d1.COL1, STRING_AGG(d2.COL2, ',') WITHIN GROUP (ORDER BY d2.COL1) AS COL2
FROM Data d1
JOIN Data d2 ON d1.COL1 >= d2.COL1
WHERE d2.COL2 IS NOT NULL
GROUP BY d1.COL1
ORDER BY d1.COL1
Result:
COL1 COL2
10 a
20 a,b
30 a,b,c
40 a,b,c
50 a,b,c,d
try the following:
declare #t table (COL1 int, COL2 varchar(max))
insert into #t select 10, 'a'
insert into #t select 20, 'b'
insert into #t select 30, 'c'
insert into #t select 40, NULL
insert into #t select 50, 'd'
select COL1, STUFF(
(
SELECT DISTINCT ',' + COL2 FROM #t t2
WHERE t.COL1 >= t2.COL1 for xml path('')
),1,1,''
) AS COL2
from #t t
SELECT ID,STUFF((SELECT DISTINCT ',' + [Values] FROM Table_ t2
WHERE t.ID>= t2.ID for xml path('')),1,1,'') AS [Values]
FROM Table_ t

find max value in a row and update new column with the max column name

I have a table like this
number col1 col2 col3 col4 max
---------------------------------------
0 200 150 300 80
16 68 250 null 55
I want to find max value between col1,col2,col3,col4 in every row and update the last column "max" with the max value column name!
for example in first row max value is 300 the "max" column value will be "col3"
result like this:
number col1 col2 col3 col4 max
------------------------------------------
0 200 150 300 80 col3
16 68 250 null 55 col2
How can I do this?
QUERY
SELECT *,(
SELECT MAX(n)
FROM
(
VALUES(col1),(col2),(col3),(col4)
) AS t(n)
) AS maximum_value
FROM #tmp
Update statement
with MaxValues
as (select [number], [max] = (
select (
select max ([n])
from (values ([col1]) , ([col2]) , ([col3]) , ([col4])) as [t] ([n])
) as [maximum_value])
from [#tmpTable])
update [#tmpTable]
set [max] = [mv].[max]
from [MaxValues] [mv]
join [#tmpTable] on [mv].[number] = [#tmpTable].[number];
assuming number is a key column
SQL Fiddle
Check in SQL Fiddle
Schema
DECLARE #temp table ([number] int NOT NULL, [col1] int, [col2] int, [col3] int, [col4] int, [colmax] int);
INSERT #temp VALUES (0, 200, 150, 300, 80, null), (16, 68, 250, null, 55, null);
Query
SELECT number
,(
SELECT MAX(col) maxCol
FROM (
SELECT t.col1 AS col
UNION
SELECT t.col2
UNION
SELECT t.col3
UNION
SELECT t.col4
) a
) col
FROM #temp t
and the update statement is -
UPDATE tempCol
SET colmax = a.col
FROM (
SELECT (
SELECT MAX(col) maxCol
FROM (
SELECT t.col1 AS col
UNION
SELECT t.col2
UNION
SELECT t.col3
UNION
SELECT t.col4
) a
) col
FROM tempCol t
) a

Select only distinct values from two columns from a table

If I have a table such as
1 A
1 B
1 A
1 B
2 C
2 C
And I want to select distinct from the two columns so that I would get
1
2
A
B
C
How can I word my query? Is the only way to concatenate the columns and wrap them around a distinct function operator?
You could use a union to create a table of all values from both columns:
select col1 as BothColumns
from YourTable
union
select col2
from YourTable
Unlike union all, union removes duplicates, even if they come from the same side of the union.
SQL Fiddle
Why even distinct in Union, try this :
select cast(id as char(1)) from test
union
select val from test
Please try:
Select Col1 from YourTable
union
Select Col2 from YourTable
UNION removes duplicate records (where all columns in the results are the same), UNION ALL does not.
Please check What is the difference between UNION and UNION ALL
For multiple columns, you can go for UNPIVOT.
SELECT distinct DistValues
FROM
(SELECT Col1, Col2, Col3
FROM YourTable) p
UNPIVOT
(DistValues FOR Dist IN
(Col1, Col2, Col3)
)AS unpvt;
Try this one -
DECLARE #temp TABLE
(
Col1 INT
, Col2 NVARCHAR(50)
)
INSERT INTO #temp (Col1, Col2)
VALUES (1, 'ab5defg'), (2, 'ae4eii')
SELECT disword = (
SELECT DISTINCT dt.ch
FROM (
SELECT ch = SUBSTRING(t.mtxt, n.number + 1, 1)
FROM [master].dbo.spt_values n
CROSS JOIN (
SELECT mtxt = (
SELECT CAST(Col1 AS VARCHAR(10)) + Col2
FROM #temp
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'
)
) t
WHERE [type] = N'p'
AND number <= LEN(mtxt) - 1
) dt
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'
)
Or try this -
DECLARE #temp TABLE
(
a CHAR(1), b CHAR(1)
)
INSERT INTO #temp (a, b)
VALUES
('1', 'A'), ('1', 'B'), ('1', 'A'),
('1', 'B'), ('2', 'C'), ('2', 'C')
SELECT a
FROM #temp
UNION
SELECT b
FROM #temp
Because what you want select is in different columns, you can use union like below:
select distinct tarCol from
(select distinct column1 as tarCol from table
union
select distinct column2 from table) as tarTab
You can use like this to get multiple distinct column values
(SELECT DISTINCT `enodeb` as res,
"enodeb" as columnname
FROM `raw_metrics`)
UNION
(SELECT DISTINCT `interval` as res,
"interval" as columnname
FROM `raw_metrics`)