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

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

Related

Need to get the value from a column whose column name is based on a value in another table

Table A has columns ID, COL1, COL2, COL3.
Table B has columns AID, ColumnName.
I need to get the [ColumnName] value in Table A based on the value of [ColumnName] in Table B.
In the example below:
For ID 1, I need to get the value of column COL1 (This is the value of [ColumnName] for AID 1 in Table B).
For ID 2, I need to get the value of column COL3 (This is the value of [ColumnName] for AID 2 in Table B).
Table A
ID COL1 COL2 COL3
1 a aa aaa
2 b bb bbb
Table B
AID ColumnName
1 COL1
2 COL3
Desired Result:
ID VALUE
1 a
2 bbb
How can I do that ?
Thank you.
Unpivot then join
drop table t
go
drop table t1
go
create table t
(ID int, COL1 varchar(10), COL2 varchar(10), COL3 varchar(10))
go
create table t1
(AID int,ColumnName varchar(10));
go
insert into t values
(1 , 'a', 'aa', 'aaa'),
(2 , 'b', 'bb', 'bbb')
go
insert into t1 values
(1 , 'COL1'),
(2 , 'COL3')
go
with cte as
(select id, u.col, u.val
from t
unpivot
(
val
for col in (col1, col2, col3)
) u
)
select cte.id,cte.val
from cte
join t1 on
t1.aid = cte.id and
t1.columnname = cte.col
go
id val
----------- ----------
1 a
2 bbb
(2 row(s) affected)
One possible approach is to unpivot the columns in TableA using VALUES table value constructor and additional APPLY operator:
Tables:
SELECT *
INTO TableA
FROM (VALUES
(1, 'a', 'aa', 'aaa'),
(2, 'b', 'bb', 'bbb')
) v (ID, COL1, COL2, COL3)
SELECT *
INTO TableB
FROM (VALUES
(1, 'COL1'),
(2, 'COL3')
) v (AID, COL)
Statement:
SELECT b.AID, v.VALUE
FROM TableB b
JOIN TableA a ON b.AID = a.ID
CROSS APPLY (VALUES
('COL1', a.COL1),
('COL2', a.COL2),
('COL3', a.COL3)
) v (COL, [VALUE])
WHERE v.COL = b.COL
Result:
AID
VALUE
1
a
2
bbb

How to get the desired output using sql

I have my DB table looks like the following
IDCol Col1 Col2 Col3
ID1 1 3 1000
ID1 6 6 1000
ID2 3 4 500
ID2 1 7 500
I need the output as the following
IDCol Col1 Col2 Col3
ID1 1 6 1000
ID2 3 7 500
Is there a possibility that I could get the above desired output format using SQL?
I am a newbie to SQL and could some one please help me? Thank you very much!
Based on your sample data, I believe this is what you're looking for:
SELECT IDCol
, MIN(Col1) AS [Col1]
, MAX(Col2) AS [Col2]
, Col3
FROM Table
GROUP BY IDCol
, Col3
Based on the information from your comments, if you add a row number column, then one of the solutions would be in the form of:
select t1.idcol
, t1.col1
, t2.col2
, t1.col3
from
(select idcol
, min(rn) over (partition by idcol) first_val
, max(rn) over (partition by idcol) last_val
from table
group by idcol, rn) r
inner join table t1 on r.first_val = t1.rn
and r.idcol = t1.idcol
inner join table t2 on r.last_val = t2.rn
and r.idcol = t2.idcol
group by t1.idcol
, t1.col1
, t2.col2
, t1.col3
Sample code running on your sample data:
declare #tbl table (rn int identity(1,1), idcol varchar(4), col1 int, col2 int, col3 int)
insert #tbl values ('id1', 1, 3, 1000)
, ('id1', 6, 6, 1000)
, ('id2', 3, 4, 500)
, ('id2', 1, 7, 500);
select t1.idcol
, t1.col1
, t2.col2
, t1.col3
from
(select idcol
, min(rn) over (partition by idcol) first_val
, max(rn) over (partition by idcol) last_val
from #tbl
group by idcol, rn) r
inner join #tbl t1 on r.first_val = t1.rn
and r.idcol = t1.idcol
inner join #tbl t2 on r.last_val = t2.rn
and r.idcol = t2.idcol
group by t1.idcol
, t1.col1
, t2.col2
, t1.col3
Another way of trying it using LEAD (supported from 2012):
declare #t1 table
(
IDCol char(5),
Col1 INT,
Col2 INT,
Col3 INT
)
Insert into #t1 values ('ID1', 3 , 3 , 1000);
Insert into #t1 values ('ID1', 6 , 6 , 1000);
Insert into #t1 values ('ID1', 6 , 4 , 1000);
Insert into #t1 values ('ID2', 11 , 3 , 1000);
Insert into #t1 values ('ID2', 6 , 6 , 1000);
Select * from
(
Select t1.IDCol, t1.Col1,
Lead(t1.Col2) Over (Partition by t1.IDCol Order By t1.IDCol) Col2,
t1.Col3 From
(
Select IDCol, Col1, Col2, Col3,
ROW_NUMBER() over(partition by IDCol order by IDCol) as RowFlg
from #t1
) t1,
(
Select IDCol, Min(RowFlg) Col1MinVal, Max(RowFlg) Col2MaxVal from
(
Select IDCol, ROW_NUMBER() over(partition by IDCol order by IDCol) as RowFlg from #t1
) z
Group By IDCol
) x
Where t1.IDCol = x.IDCol AND (t1.RowFlg = x.Col1MinVal OR t1.RowFlg = x.Col2MaxVal)
) main
Where Col2 is not null
I think you have to specify the level of abstraction for this task. You can achieve this output using many statements. The questions are what does the data rows represent and why the demanded output should be expected.

Get top n row of each group of two columns

This question is different from Get top 1 row of each group. In my question, each group is consists of two columns (col1, col2), while in his question each group is consists of only one column (col1). I also tried to modify the answer in his question but failed.
Example:
Suppose n = 1
Input:
col1 col2 x Amt
A B x1 100
A B x2 200
C D x3 400
C D x4 500
...more data ...
Output:
col1 col2 x Amt
A B x2 200
C D x4 500
...more data ...
What I tried ...select *, row_numne() over ( partition by (col1, col2) order by ...
You can still use row_number within a CTE. The idea is to get all the rows, per your grouping, that is <= the number you pass in. This is similar to getting the top n rows for your pairing based on the order of AMT
declare #count int = 1
with cte as(
select
col1,
col2,
x,
Amt,
row_number() over (partition by col1, col2 order by Amt desc) as rn
from yourTable)
select
col1,
col2,
x,
Amt
from cte
where rn <= #count
why not simple max works for you?
select col1, col2, max(x), Max(Amt) from yourtable
group by col1, col2
Declare #Top int = 1
Select col1,col2,x,Amt
From (
Select *
,RN=Row_Number() over (Partition By Col1,Col2 Order By Amt Desc)
From YourTable ) A
Where RN<=#Top
Returns
col1 col2 x Amt
A B x2 200
C D x4 500
And here is the CROSS APPLY option, with test tables to confirm its functionality:
DECLARE #MyTable TABLE (Col1 varchar(4) not null, Col2 varchar(4) not null, x varchar(8) not null, amt int not null)
INSERT INTO #myTable VAlues ('A', 'B', 'x1', 100)
INSERT INTO #myTable VAlues ('A', 'B', 'x2', 200)
INSERT INTO #myTable VAlues ('C', 'D', 'x4', 400)
INSERT INTO #myTable VAlues ('C', 'D', 'x3', 500)
DECLARE #n int
SET #n = 1
SELECT DISTINCT
m.Col1,
m.Col2,
m2.x,
m2.Amt
FROM #MyTable m
CROSS APPLY (
SELECT TOP(#n) Amt, x
FROM #MyTable
WHERE col1 = m.Col1
AND col2 = m.col2
ORDER BY Amt Desc, x Desc
) m2

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`)