56

我想知道如果列存在,我是否可以选择列的值,否则只选择 null 。换句话说,我想“提升”选择语句来处理列不存在的情况。

SELECT uniqueId
    ,  columnTwo
    ,  /*WHEN columnThree exists THEN columnThree ELSE NULL END*/ AS columnThree
FROM (subQuery) s

请注意,我正在巩固我的数据模型和设计。我希望在接下来的几周内排除这种逻辑,但我真的很想超越这个问题,因为数据模型修复比我现在想解决的更耗时。

另请注意,我希望能够在一个查询中执行此操作。所以我不是在寻找像

首先检查您的子查询中有哪些列。然后修改您的查询以适当处理子查询中的列。

4

3 回答 3

33

您无法使用简单的 SQL 语句来做到这一点。除非表中的所有表和列引用都存在,否则 SQL 查询不会编译。

如果“子查询”是表引用或视图,您可以使用动态 SQL 执行此操作。

在动态 SQL 中,您可以执行以下操作:

declare @sql nvarchar(max) = '
SELECT uniqueId, columnTwo, '+
    (case when exists (select *
                       from INFORMATION_SCHEMA.COLUMNS 
                       where tablename = @TableName and
                             columnname = 'ColumnThree' -- and schema name too, if you like
                      )
          then 'ColumnThree'
          else 'NULL as ColumnThree'
     end) + '
FROM (select * from '+@SourceName+' s
';

exec sp_executesql @sql;

对于实际的子查询,您可以通过检查子查询是否返回具有该列名的内容来近似相同的内容。一种方法是运行查询: select top 0 * into #temp from (<subquery>) s然后检查#temp.

编辑:

我通常不会更新这些老问题,而是根据下面的评论。如果“子查询”中的每一行都有唯一标识符,则可以运行以下命令:

select t.. . .,  -- everything but columnthree
       (select column3   -- not qualified!
        from t t2
        where t2.pk = t.pk
       ) as column3
from t cross join
     (values (NULL)) v(columnthree);

column3如果不存在,子查询将从外部查询中提取。然而,这主要取决于每一行都有一个唯一的标识符。这个问题明确地是关于子查询的,没有理由期望这些行很容易被唯一地识别。

于 2013-06-06T01:44:53.843 回答
27

正如其他人已经建议的那样,理智的方法是让查询满足您的表设计。

不过,有一种相当奇特的方法可以在(纯的,非动态的)SQL 中实现您想要的。DBA.SE 上发布了一个类似的问题:如果存在列,则如何选择特定行,如果列不存在,则选择所有行,但它更简单,因为结果只需要一行和一列。您的问题更复杂,因此查询更复杂,至少可以这么说。这是疯狂的方法:

; WITH s AS
  (subquery)                                    -- subquery
SELECT uniqueId
    ,  columnTwo
    ,  columnThree =
       ( SELECT ( SELECT columnThree 
                  FROM s AS s2
                  WHERE s2.uniqueId = s.uniqueId
                ) AS columnThree
         FROM (SELECT NULL AS columnThree) AS dummy
       )
FROM s ;

它还假设uniqueId在子查询的结果集中是唯一的。

SQL-Fiddle测试


还有一种更简单的方法,它具有额外的优势,允许一个以上的列具有单个子查询:

SELECT s.*     
FROM
    ( SELECT NULL AS columnTwo,
             NULL AS columnThree,
             NULL AS columnFour
    ) AS dummy 
  CROSS APPLY
    ( SELECT 
          uniqueId,
          columnTwo,
          columnThree,
          columnFour
      FROM tableX
    ) AS s ;

DBA.SE 也提出了这个问题,@ Andriy M(也使用CROSS APPLY了!)和Michael Ericsson(使用XML)回答了这个问题:
为什么我不能使用 CASE 语句来查看列是否存在而不是从中选择?

于 2013-07-11T09:08:46.967 回答
4

您可以使用动态 SQL。

首先您需要检查存在,然后创建动态查询。

DECLARE @query NVARCHAR(MAX) = '
SELECT FirstColumn, SecondColumn, '+
  (CASE WHEN exists (SELECT 1 FROM syscolumns 
  WHERE name = 'ColumnName' AND id = OBJECT_ID('TableName'))
      THEN 'ColumnName'
      ELSE 'NULL as ThreeColumn'
   END) + '
FROM TableName'

EXEC sp_executesql @query;
于 2019-09-23T06:39:39.890 回答