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

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

Related

WHERE IN clause in temporary columns?

I have a query that creates two temporary columns. Is there a way to check if column 2 value exists in column 1 value?
select x as column1, y as column 2
Result:
column 1 | column 2
x y
w x
how do I check if x exists in column 1 ? Ultimately I only want to get all the values in column 2 that do not have a matching value in column 1, Is this possible?
You can use EXCEPT for this:
Declare #testTable Table (col1 varchar(10), col2 varchar(10));
Insert Into #testTable (col1, col2)
Values ('x', 'y')
, ('w', 'x');
Select col2 From #testTable tt
Except
Select col1 From #testTable tt;

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

How to write a SQL query for the below?

I have two tables with n of columns from Col1 to Col30
Table 1.
Templateid Col1 Col2 Col3 Col4 ...
95 2019-05-28 1234 test123 123456
Table 2.
Templateid DisplayName ColumnName
95 date col1
95 rank col2
95 purpose col3
95 sign col4
Expected Results.
Col1Name Col1Value Col2Name Col2Value Col3Name Col3Value ....
date 2019-05-28 rank 1234 purpose test123
This is a crude way of doing it and if you do not know the number of columns in each table you would need to use dynamic sql to enumerate them out but for the purposes of this example I have assumed you do know the number of columns and the names you want to populate.
The union query allows you to pre-populate the desired column names using the col1 syntax, then the pivot allows you to match up the displaynames and the display values. A case statement is required to ensure the correct values are shown and you do need to populate your derived column names for the pivot query but you do get the desired outcome this way.
declare #table1 table (
Templateid int,
Col1 date,
col2 int,
col3 nvarchar(10),
col4 int
);
insert into #table1 (Templateid, col1, col2, col3, col4)
values
(95, '2019-05-28', '1234', 'test123', '123456');
declare #table2 table (
Templateid int,
Displayname nvarchar(10),
ColumnName nvarchar(10)
);
insert into #table2 (Templateid, Displayname, ColumnName)
values
(95, 'date', 'col1'),
(95, 'rank', 'col2'),
(95, 'purpose', 'col3'),
(95, 'sign', 'col4');
select * from
(
select columnname+'Name' as columnname, Displayname
from #table2 t2
union
select columnname+'Value', case when columnname='col1' then cast(col1 as nvarchar(15))
when columnname='col2' then cast(col2 as nvarchar(15))
when columnname='col3' then cast(col3 as nvarchar(15))
when columnname='col4' then cast(col4 as nvarchar(15)) end
from #table1 t1 inner join #table2 t2 on t1.Templateid=t2.Templateid) src
pivot
(max(displayname) for columnname in ([col1Name],[col1Value], [col2Name],[col2Value], [col3Name],[col3Value], [col4Name],[col4Value])) piv;

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

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