【问题标题】:SQL- How to write dynamic where cluse using table valuesSQL-如何使用表值编写动态 where 子句
【发布时间】:2012-11-20 01:44:31
【问题描述】:

我有一个临时表,例如:#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)
我是怎么做的。提前致谢

【问题讨论】:

  • 由于列数可能不同,另一个表是否有尽可能多的列来匹配,并且总是以相同的顺序,具有相同的名称?? #temp321 是否只有 1 行?
  • 是的。列数将始终相同。请帮我只写where子句。

标签: sql sql-server tsql dynamic-sql


【解决方案1】:

你可以这样做:

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 条件。请注意它。我使用了列的ORDINAL_POSITIONs,它是存储在表information_schema.columns 中的元数据,用于数据库中的每一列,来比较两个表中的列名列表。例如,具有普通位置 1 的列将与来自第二个表的具有普通位置 1 的列名连接,依此类推。因此,您必须注意临时表列的位置,以便列与第二个表的其他列列表的顺序相同。


更新2:

动态生成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 子句,我将UNPIVOT将此行分成两列:fieldname: 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 子句,动态UNPIVOTing 临时表的值:

但是前面的方法有一个很大的问题。的选择 您需要像这样动态地取消透视表临时:

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

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

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

这里是更新后的带有动态 unpivot 的 sql:

DECLARE @DynamicWHERECondition AS NVARCHAR(MAX);
DECLARE @cols AS NVARCHAR(MAX);
DECLARE @dynamicunpivotquery AS NVARCHAR(MAX);
DECLARE @query AS NVARCHAR(MAX);
DECLARE @unpivotedTable TABLE(FieldName varchar(50), fieldvalue VARCHAR(50));

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 ';

INSERT INTO  @unpivotedTable
exec(@dynamicunpivotquery);

;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  @unpivotedTable 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);

【讨论】:

  • 用户如何使用Field24 = 'Value2'?。我认为他正在寻找动态查询...
  • 当然。感谢您的努力。
  • @Gamal。我在等……需要你的帮助。
  • @Gamal.非常感谢您的努力。但是你能帮我只写where子句吗?因为我需要使用where子句来处理许多其他提议。我将非常感谢你,如果你能帮我只写where子句。希望你能得到我.
  • @riad - 好的,我会更新我的答案,但是两个表中的列位置是否相同? IE。我将按照生成 JOIN 条件的相同方式生成 where 子句,以便临时表中的第 1 列与另一个表的第 1 列的值进行比较,依此类推。这是正确的吗?
猜你喜欢
  • 2019-08-08
  • 2022-01-25
  • 1970-01-01
  • 2010-09-13
  • 2014-03-03
  • 1970-01-01
  • 2013-11-13
  • 1970-01-01
  • 2018-02-01
相关资源
最近更新 更多