SQL-如何使用表值编写动态where子句

时间:2012-11-19 11:18:21

标签: sql sql-server tsql dynamic-sql

我有一个临时表:#temp321

select * from #temp321

它的返回值如

Field1|Field2|Field3|....|FieldN|
--------------------------------
Value1|Value2|Value3|....|ValueN|

这个#temp321表是从另一组查询中自动生成的。因此,#temp321表的列数可以变化(1-25)。但他们将永远是一排。现在我需要使用这些值写一个where语句 示例:
 where Field1='Value1' and Field2='Value2' and Field3='Value3'.....FieldN='ValueN'..(depends on number of column available into the #temp321 table)
我是怎么做的提前致谢

1 个答案:

答案 0 :(得分:5)

你可以这样做:

SELECT *
FROM Othertable t1
INNER JOIN #temp321 t2 ON  t1.Field1 = t2.field1 
     AND t1.Field2 = t2.field2 
     AND t1.Field3 = t2.field3;

更新:这就是我能做的:

JOIN两个表动态而不是WHERE子句:

DECLARE @DynamicJOINCondition AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);

;WITH cte
AS
(
    SELECT t1.COLUMN_NAME 'T1', t2.COLUMN_NAME 'T2'
    FROM 
    (
       SELECT 
         ordinal_position , 
         column_name
       FROM information_schema.columns 
       WHERE table_name LIKE '#temp321%'
    ) t1
    INNER JOIN
    (
       SELECT 
         ordinal_position , 
         column_name
       FROM information_schema.columns 
       WHERE table_name = 'othertable'
    ) t2 ON t1.ORDINAL_POSITION = t2.ORDINAL_POSITION
)
SELECT @DynamicJOINCondition = STUFF((SELECT distinct ' AND ' +  
                     ' t1.' + T1 + ' = ' + 't2.' + T2
               FROM cte
               FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)'), 4,1,'');

-- Remove the first AND
SELECT @DynamicJOINCondition = RIGHT(@DynamicJOINCondition, 
                                     LEN(@DynamicJOINCondition) - 4);

SET @query = 'SELECT COUNT(*) ' +
             ' FROM  #temp321 t1 INNER JOIN Othertable t2 ON ' +
               @DynamicJOINCondition;

EXECUTE(@query);

这是如何运作的?

首先,我通过从临时表中获取列名列表以及从另一个表中获取列名的其他列表来动态生成JOIN条件。请注意它。我使用列{'{1}} s,它是存储在表ORDINAL_POSITION中的元数据,用于数据库中的每一列,以比较两个表中的列名列表。对于exapmle,带有adjcary postition 1的列将与列名称连接,而第二个表中的普通位置1也是如此。因此,您必须注意临时表列的位置,以便列出的列与第二个表的其他列列表的顺序相同。


更新2:

动态生成information_schema.columns子句:

如果要动态生成WHERE子句而不是WHERE,则在这种情况下需要更多工作。像这样:

JOIN

这是如何运作的?

由于临时表只包含一行,其中的值将用于形成动态创建的DECLARE @DynamicWHERECondition AS NVARCHAR(MAX); DECLARE @query AS NVARCHAR(MAX); ;WITH cte AS ( SELECT t1.COLUMN_NAME 'T1', t2.COLUMN_NAME 'T2' FROM ( SELECT ordinal_position, column_name FROM information_schema.columns WHERE table_name LIKE '#temp321%' ) t1 INNER JOIN ( SELECT ordinal_position, column_name FROM information_schema.columns WHERE table_name = 'othertable' ) t2 ON t1.ORDINAL_POSITION = t2.ORDINAL_POSITION ), cte2 AS ( SELECT t2, fieldvalue FROM cte t1 INNER JOIN ( SELECT FieldName, fieldvalue FROM ( SELECT field1, field2, field3, field4 FROM #temp321 ) p UNPIVOT ( fieldvalue FOR FieldName IN (field1, field2, field3, field4) ) AS u ) t2 ON t1.T2 = t2.FieldName ) SELECT @DynamicWHERECondition = STUFF((SELECT distinct ' AND ' + T2 + ' = ' + '''' + fieldvalue + '''' FROM cte2 FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 4,1,''); SELECT @DynamicWHERECondition = RIGHT(@DynamicWHERECondition, LEN(@DynamicWHERECondition) - 4); SET @query = 'SELECT COUNT(*) ' + ' FROM Othertable t2 WHERE ' + @DynamicWHERECondition; EXECUTE(@query); 子句,因此WHERE将这一行编辑为两列:UNPIVOTfieldname: field1, field2, ...

后来我加入了这个不透明的专栏,其中包含我在第一次查询中使用的两个表:

fieldvalue: value1, value2, ...

    SELECT
      ordinal_position, 
      column_name
    FROM information_schema.columns 
    WHERE table_name LIKE '#temp321%';

连接条件与第一种情况中的条件相同,即两个表中列的序号位置。


动态生成 SELECT ordinal_position, column_name FROM information_schema.columns WHERE table_name = 'othertable'; 子句,动态WHERE临时表的值:

但是之前的方法存在很大问题。选择 您需要像下面那样动态地取消表格温度:

UNPIVOT

但是,为了在我们的查询中稍后使用动态不透明的表,你必须创建一个临时表:

SELECT @cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(column_name)
                  FROM information_schema.columns 
                  WHERE table_name LIKE '#temp321%'
                  FOR XML PATH(''), TYPE
                  ).value('.', 'NVARCHAR(MAX)'), 1, 1, '');

SET @dynamicunpivotquery = ' SELECT FieldName, fieldvalue ' +
                           ' FROM ' +
                           ' ( SELECT * FROM #temp321 ' +
                           ' ) p ' +
                           ' UNPIVOT ' +
                           ' ( ' + 
                           '   fieldvalue FOR FieldName IN (' + @cols + ' ) ' +
                           ' ) AS u ';

所以你可以像这样使用它:

DECLARE @unpivotedTable TABLE(FieldName varchar(50), fieldvalue VARCHAR(50));
INSERT INTO  @unpivotedTable
exec(@dynamicunpivotquery);

这是使用动态unpivot的更新的sql:

SELECT t2, fieldvalue
FROM cte t1
INNER JOIN  @unpivotedTable t2 ON t1.T2 = t2.FieldName