简体   繁体   中英

SQL Server, Dynamically join using the column name and value from same table with a different table

I have two tables as below that I am looking to join dynamically using the ColVal in TMaster with ColName in TMaster which is the name of the column to match with in TTable1.

TMaster:

在此处输入图片说明

TTable1:

在此处输入图片说明

So, final result would be the data from TTable1 that matches the colName and ColVal in TMaster. How do I achieve this?

select tt.Name 
from TMaster tm 
join TTable1 tt on TMaster.ColVal = tt.[ColName from TMaster should be used here]

Why not :

SELECT tt.Name 
FROM   TMaster AS tm
       JOIN TTable1 AS tt 
          ON tm.ColVal = CASE ColVal 
                             WHEN 1 THEN tt.Col1
                             WHEN 2 THEN tt.Col2
                             WHEN 3 THEN tt.Col3
                          END

You can formulate your query in the following manner

SELECT tt.Name 
FROM TMaster tm
JOIN TTable1 tt ON 
    tm.ColName = 'Col1' AND tm.ColVal = tt.Col1 OR
    tm.ColName = 'Col2' AND tm.ColVal = tt.Col2 OR
    tm.ColName = 'Col3' AND tm.ColVal = tt.Col3 OR
....

It's not going to be very performant though.

If you do not even know your column names (why that should be, I don't know) then you need dynamic SQL.

DECLARE @sql nvarchar(max) = '
SELECT tt.Name 
FROM TMaster tm
JOIN TTable1 tt ON 
' +
(
    SELECT STRING_AGG(CAST(
'    tm.ColName = ' + QUOTENAME(c.name, '''') + ' AND tm.ColVal = tt.' + QUOTENAME(c.name)
    AS nvarchar(max)), N' OR
'
    )
    FROM sys.columns
    WHERE OBJECT_NAME(object_id) = 'TTable1'
);

PRINT @sql; -- for testing

EXEC sp_executesql @sql;

One solution is to use a query such as this:

SELECT TMaster.*, x.Name
FROM TTable1
CROSS APPLY (VALUES
    ('ID',  ID,  Name),
    ('ID2', ID2, Name),
    ('ID3', ID3, Name),
    ('ID4', ID4, Name)
) AS x(ColName, ColVal, Name)
JOIN TMaster ON TMaster.ColName = x.ColName AND TMaster.ColVal = x.ColVal

Or this variant which could produce a smaller number of rows:

FROM (
    SELECT 'ID',  ID,  Name FROM TTable1 WHERE ID  IS NOT NULL UNION ALL
    SELECT 'ID2', ID2, Name FROM TTable1 WHERE ID2 IS NOT NULL UNION ALL
    SELECT 'ID3', ID3, Name FROM TTable1 WHERE ID3 IS NOT NULL UNION ALL
    SELECT 'ID4', ID4, Name FROM TTable1 WHERE ID4 IS NOT NULL
) AS x(ColName, ColVal, Name)

The list of (column name, column value) pairs should contain all columns that exist in TTable1; possibly restricted to the names that exist in TMaster.ColName .

If the datatype of columns ID, ID2, ID3, ... is different you need to match the datatype x.ColVal to match that of TMaster.ColVal :

CROSS APPLY (VALUES
    ('ID',  CAST(ID  AS VARCHAR(200)), Name),
    ('ID2', CAST(ID2 AS VARCHAR(200)), Name),

Finally, the (column name, column value) pairs could instead be converted to a view (which could be materialized I think) and then you can join with it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM