column to row in sql server? - sql

Table:
CREATE TABLE Table1 (
col1 INT,
col2 nvarchar(10),
col3 INT,
col4 INT
);
INSERT INTO Table1
(col1, col2, col3, col4)
VALUES
(1, 'welcome', 3, 4);
My table have different data type , col2 is nvarchar h can i do this ...
result:
col value
---------------
col1 1
col2 welcome
col3 3
col4 4

You can use the UNPIVOT operation to get your results
SELECT col, value
FROM
(SELECT CAST(col1 AS VARCHAR) AS col1, CAST(col2 AS VARCHAR) AS col2,
CAST(col3 AS VARCHAR) AS col3, CAST(col4 AS VARCHAR) AS col4
FROM Table1) p
UNPIVOT
(value FOR col IN
(col1, col2, col3, col4)
) AS unpvt;

Use:
SELECT 'col1' AS col,
CAST(t1.col1 AS NVARCHAR(10)) AS value
FROM TABLE_1 t1
UNION ALL
SELECT 'col2' AS col,
t2.col2 AS value
FROM TABLE_1 t2
UNION ALL
SELECT 'col3' AS col,
CAST(t3.col3 AS NVARCHAR(10)) AS value
FROM TABLE_1 t3
UNION ALL
SELECT 'col4' AS col,
CAST(t4.col4 AS NVARCHAR(10)) AS value
FROM TABLE_1 t4
Part of the problem is that you need to make the second column the same data type:
CAST/CONVERT

with rows(n)
as
(
select 1
union all
select n + 1
from rows
where n + 1 <= 4
)
select case n
when 1 then 'col1'
when 2 then 'col2'
when 3 then 'col3'
when 4 then 'col4'
end as col,
case n
when 1 then col1
when 2 then col2
when 3 then col3
when 4 then col4
end as value
from
(
select cast (col1 as varchar) col1,
col2,
cast (col3 as varchar) col3,
cast (col4 as varchar) col4,
n
from table1, rows
) x

Related

Get columns from another column

I have the following table :
ColID Columns
1 SELECT Col1, Col2, Col3, Col4, Col5 FROM MyTab
I want to get the column names between SELECT and FROM.
CREATE TABLE dbo.Mytab(ColID int, Columns varchar(max))
INSERT INTO dbo.Mytab(ColID,Columns)
VALUES(1,'SELECT Col1, Col2, Col3, Col4, Col5 FROM MyTab')
GO
SELECT SUBSTRING(Columns, CHARINDEX('SELECT', Columns) +6
, CHARINDEX('FROM',Columns) - CHARINDEX('SELECT', Columns) - Len('FROM')-2)
FROM dbo.Mytab
| (No column name) |
| :----------------------------- |
| Col1, Col2, Col3, Col4, Col5 |
db<>fiddle here
If this is a query that you need the columns for, you can get them with dm_exec_describe_first_result_set:
select name from sys.dm_exec_describe_first_result_set ( #myQuery, #parameters, 0)
If it is just a table, you can use sys.columns:
select name from sys.columns where object_id = object_id('dbo.myTable')
To get it as a nice table I improved(think so :-) ) the fiddle above
Setup:
CREATE TABLE dbo.Mytab(ColID int, Columns varchar(max))
INSERT INTO dbo.Mytab(ColID,Columns)
VALUES(1,'SELECT Col1, Col2, Col3, Col4, Col5 FROM MyTab');
INSERT INTO dbo.Mytab(ColID,Columns)
VALUES(2,'SELECT Col3, Col4, Col5, Col6 FROM MyTab')
Query:
select m.colid, p.value from dbo.myTab m CROSS APPLY string_split((SELECT SUBSTRING(m.Columns, CHARINDEX('SELECT',m.Columns) +6
, CHARINDEX('FROM',m.Columns) - CHARINDEX('SELECT', m.Columns) - Len('FROM')-2) ) ,',') as p
Result:
colid
value
1
Col1
1
Col2
1
Col3
1
Col4
1
Col5
2
Col3
2
Col4
2
Col5
2
Col6

I have a unique or distinct recors in all the column, table

I need a unique record all the table and all the column how can I get
Table1
Col1 col2 col3 col4 col5
A. P. 20. 21
B. Q. 18. 19
C. R 17. 16
Table2
Col1 col2 col3 col4 col5
A. P. 51 58
B. Q. 60 65
C. R 18 25
D. S. 33. 31
Table3
Col1 col2 col3 col4 col5
A. P. 60. 13
B. Q. 75 61
E t 100 108
F. U. 91. 98
Output of table (I need like dz output)
Col1 col2 col3 col4 col5
A. P. 20. 21
B. Q. 18. 19
C. R 17. 16
D. S. 33. 31
E. T. 100 108
F. U. 91. 98
To get all the unique rows you can combine all the records from all three tables using union all and use distinct to get unique rows.
select distinct col2 ,col3 ,col4 ,col5 from (
select col2 ,col3 ,col4 ,col5 from Table1
union all
select col2 ,col3 ,col4 ,col5 from Table2
union all
select col2 ,col3 ,col4 ,col5 from Table3 )T
Or if you wan to show first record of each unique col1 and col2 value as in your output table use below query (I didn't use Col1 in the query since it's serial number for that table only):
with cte as (
select row_number() over (partition by Col2,Col3 order by sl)rn, col2 ,col3 ,col4 ,col5 from (
select 1 sl, col2 ,col3 ,col4 ,col5 from Table1
union all
select 2 sl, col2 ,col3 ,col4 ,col5 from Table2
union all
select 3 sl ,col2 ,col3 ,col4 ,col5 from Table3 )T
)select row_number() over (order by col1),Col1,Col2, Col3, Col4 from cte where rn=1
You seem to want the first result based on the first two columns. One method uses union all:
select col1, col2, col3, col4
from table1
union all
select col1, col2, col3, col4
from table2 t2
where not exists (select 1 from table1 t1 where t1.col1 = t2.col1 and t1.col2 = t2.col2)
union all
select col1, col2, col3, col4
from table3 t3
where not exists (select 1 from table1 t1 where t1.col1 = t3.col1 and t1.col2 = t3.col2) and
not exists (select 1 from table2 t2 where t2.col1 = t3.col1 and t2.col2 = t3.col2) ;
You can also do this with row_number():
select col1, col2, col3, col4k
from (select t.*,
row_number() over (partition by col1, col2 order by which) as seqnum
from ((select 1 as which, col1, col2, col3, col4
from table1
) union all
(select 2 as which, col1, col2, col3, col4
from table2
) union all
(select 3 as which, col1, col2, col3, col4
from table3
)
) t
) t
where seqnum = 1;
With an index on (col1, col2) in each of the tables, I would expect the first version to be faster.

SQL Server : if column is not null show as a new row

I have a table like this:
id name col1 col2 col3 col4 col5 col6
----------------------------------------------
1 user b c e f g Null
I want to display the results like this as col4 and col5 is not null but do not show col6 as it is null:
id name col1 col2 col3 col4
----------------------------------
1 user b c e f
1 user b c e g(from col5)
You can use UNPIVOT for this. This automatically excludes NULL
SELECT id,
name,
col1,
col2,
col3,
ucol AS col4
FROM YourTable
UNPIVOT (x
FOR ucol IN (col4,
col5,
col6)) u
With UNION:
SELECT id, name, col1, col2, col3, col4 FROM tablename
UNION
SELECT id, name, col1, col2, col3, col5 FROM tablename
you can add to the 2nd select:
WHERE col5 IS NOT NULL
if this is what you want.
I would use cross apply:
select v.*
from t cross apply
(values (id, name, col1, col2, col3, col4),
(id, name, col1, col2, col3, col5)
) v(id, name, col1, col2, col3, col4);
If you want to unpivot and explicitly exclude null values:
select v.*
from t cross apply
(values (id, name, col1, col2, col3, col4),
(id, name, col1, col2, col3, col5),
(id, name, col1, col2, col3, col6)
) v(id, name, col1, col2, col3, col4)
where col4 is not null;

concatenate and de-dupe multiple rows

I have some incoming rows in the below format.
| Col1 | Col2 | Col3 |
| 1 | A | 1 |
| 1 | A | 1,2 |
| 1 | A | 1,3 |
| 1 | A | 2,4 |
Desired outputsql is
| Col1 | Col2 | Col3 |
| 1 | A | 1,2,3,4 |
Basically, group all rows based on Col1 and Col2 and then concatenate and remove duplicates from Col3.
SELECT COL1, COL2, {?????}
FROM TABLEA
GROUP BY COL1, COL2;
I could not think much at this moment. Any pointers would be much appreciated. I am inclined to WX2 database, but any ANSI compliant snippet would be helpful.
For Postgres use this:
select col1, col2, string_agg(distinct col3, ',') as col3
from (
select col1, col2, x.col3
from tablea, unnest(string_to_array(col3, ',')) as x(col3)
) t
group by col1, col2;
This is largely ANSI compliant except for the string_to_array() and string_agg() function.
You could try with transpose or concatenation functions. The difficulty comes from the fact that col3 is varchar and a conversion is needed to get the distinct values.
With MySQL :
SELECT col1, col2, GROUP_CONCAT(DISTINCT col3) AS col3 FROM
(SELECT col1, col2, CONVERT(SUBSTR(col3, 1), UNSIGNED INTEGER) AS col3 FROM (
SELECT 1 AS col1, 'A' AS col2, '1' AS col3 UNION ALL
SELECT 1 AS col1, 'A' AS col2, '1,2' AS col3 UNION ALL
SELECT 1 AS col1, 'A' AS col2, '1,3' AS col3 UNION ALL
SELECT 1 AS col1, 'A' AS col2, '2,4' AS col3
) AS t
UNION ALL
SELECT col1, col2, CONVERT(SUBSTR(col3, 3), UNSIGNED INTEGER) AS col3 FROM (
SELECT 1 AS col1, 'A' AS col2, '1' AS col3 UNION ALL
SELECT 1 AS col1, 'A' AS col2, '1,2' AS col3 UNION ALL
SELECT 1 AS col1, 'A' AS col2, '1,3' AS col3 UNION ALL
SELECT 1 AS col1, 'A' AS col2, '2,4' AS col3
) AS t1
) AS t2
WHERE col3 <> 0
Result :
col1 | col2 | col3
1 | A | 1,2,3,4
For SQL Server: first concatenate all col3 values using STUFF method and INSERT INTO CTE table.Based on this CTE tables split all rows as individual into single column based on CTE table.Finally concate all DISTINCT strings with help of STUFF.
CREATE TABLE #table ( Col1 INT , Col2 VARCHAR(10) , Col3 VARCHAR(10))
INSERT INTO #table ( Col1 , Col2 , Col3 )
SELECT 1 , 'A' , '1' UNION ALL
SELECT 1 , 'A' , '1,2' UNION ALL
SELECT 1 , 'A' , '1,3' UNION ALL
SELECT 1 , 'A' , '2,4'
;WITH CTEValues ( Colval ) AS
(
SELECT STUFF ( ( SELECT ',' + Col3 FROM #table T2 WHERE T2.Col2 =
T1.col2 FOR XML PATH('') ),1,1,'')
FROM #table T1
GROUP BY Col2
)
SELECT * INTO #CTEValues
FROM CTEValues
;WITH CTEDistinct ( SplitValues , SplitRemain ) AS
(
SELECT SUBSTRING(Colval,0,CHARINDEX(',',Colval)),
SUBSTRING(Colval,CHARINDEX(',',Colval)+1,LEN(Colval))
FROM #CTEValues
UNION ALL
SELECT CASE WHEN CHARINDEX(',',SplitRemain) = 0 THEN SplitRemain ELSE
SUBSTRING(SplitRemain,0,CHARINDEX(',',SplitRemain)) END,
CASE WHEN CHARINDEX(',',SplitRemain) = 0 THEN '' ELSE
SUBSTRING(SplitRemain,CHARINDEX(',',SplitRemain)+1,LEN(SplitRemain))
END
FROM CTEDistinct
WHERE SplitRemain <> ''
)
SELECT STUFF ( ( SELECT DISTINCT ',' + SplitValues FROM CTEDistinct T2
FOR XML PATH('') ),1,1,'')

Rows to Columns and viceversa in SQL

I am very new to sql and I need a better approach for the below scenario.
Table
And I need to convert to below result.
You can try using unpivot. Here is the sample demo with data.
DECLARE #Table TABLE (
ID INT
,COL1 VARCHAR(3)
,COL2 VARCHAR(3)
,COL3 VARCHAR(3)
,COL4 VARCHAR(3)
)
INSERT INTO #TABLE VALUES
(1,'yes',null,'yes',null)
,(2,null,'yes',null,'yes')
,(3,null,null,'yes',null)
,(4,null,null,null,null)
,(5,null,'yes','yes',null)
,(6,null,null,null,null)
,(7,null,null,null,'yes')
SELECT id
,yes
FROM (
SELECT id
,col1
,col2
,col3
,col4
FROM #TABLE
where coalesce(col1, col2, col3, col4) is not null
) AS cp
UNPIVOT(yes FOR col IN (
col1
,col2
,col3
,col4
)) AS up
union
select id, null from #TABLE
where coalesce(col1, col2, col3, col4) is null
order by id
Do a UNION ALL, one select for each coln, and finally one SELECT for rows without any yes at all.
select id, 'col1' from tablename where col1 = 'yes'
union all
select id, 'col2' from tablename where col2 = 'yes'
union all
select id, 'col3' from tablename where col3 = 'yes'
union all
select id, 'col4' from tablename where col4 = 'yes'
union all
select id, cast(null as char(4)) from tablename
where 'yes' not in (coalesce(col1, 'x'),
coalesce(col2, 'x'),
coalesce(col3, 'x'),
coalesce(col4, 'x'))
If the only value is 'yes' (or NULL), then the last select can be done as
select id, cast(null as char(4)) from tablename
where coalesce(col1, col2, col3, col4) is null
Also, you can do it as the below.
;WITH CTE
AS
(
SELECT
B.ID,
B.yes,
B.col
FROM
(SELECT ID ,
ISNULL(COL1, '') COL1 ,
ISNULL(COL2, '') COL2,
ISNULL(COL3, '') COL3 ,
ISNULL(COL4, '') COL4
FROM #Tbl) A
UNPIVOT
(
col
FOR yes in (col1, col2, col3, col4)
) B
)
SELECT CTE.ID, CTE.yes FROM CTE
WHERE col = 'yes'
UNION ALL
SELECT DISTINCT ID, '' FROM CTE A
WHERE NOT EXISTS
(
SELECT 1 FROM CTE B WHERE
B.ID = A.ID AND
B.col = 'yes'
)
Result:
ID yes
----------- -----
1 COL1
1 COL3
2 COL2
2 COL4
3 COL3
4
5 COL2
5 COL3
6
7 COL4