【问题标题】:Select columnValue if the column exists otherwise null如果列存在则选择 columnValue 否则为 null
【发布时间】:2013-06-01 21:24:22
【问题描述】:

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

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

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

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

这样的答案

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

【问题讨论】:

  • 你为什么要编写假设你的数据模型将是随意的代码?为什么不对现在存在的列进行编码,当 ColumnThree 成为数据模型中的永久一等公民时,修复查询?此外,我强烈建议不要告诉人们你不想要的东西。你所说的限制是不可能满足的,你需要给出一个比这更好的理由。当您可以将事物封装在存储过程中时,“一次查询”就没有什么意义了。
  • @AaronBertrand 你问了两个问题,所以我会解决这两个问题。首先,我的目标是尽快发布高质量的功能。现在我需要来自ColumnThree 的值(当它们存在时)才能使我的功能正常工作。所以我会在它存在时使用它......即使解决方案并不优雅。
  • @AaronBertrand 其次,我很欣赏你的建议,但很不同意。我想清楚地表达我的要求,以便用户可以专注于建议解决我的问题的解决方案,而不会浪费时间写出我知道会不满意的答案。我认为准确地说明什么不是一个令人满意的答案有助于用户专注于更有价值的解决方案。

标签: sql sql-server select exists


【解决方案1】:

您无法使用简单的 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 不存在,子查询将从外部查询中获取。然而,这主要取决于每一行都有一个唯一的标识符。这个问题明确地是关于子查询的,没有理由期望这些行很容易被唯一标识。

【讨论】:

  • 我不这么认为。出于好奇,我将如何使用动态 SQL 来做到这一点?
  • 你将你的sql语句构建为一个字符串,然后使用exec命令来执行你构建的字符串。
  • 而且根据我对动态sql的理解,那不是需要两个查询吗?
  • 对,您需要一个查询来查看该字段是否存在,如果存在,请将一个字符串附加到您可以执行的动态查询中。
  • @Gordon +1 虽然它可以完成(请参阅我的回答CROSS APPLY
【解决方案2】:

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

不过,有一种相当奇特的方法可以在(纯的,非动态的)SQL 中实现您想要的。 DBA.SE 上发布了一个类似的问题:How to select specific rows if a column exists or all rows if a column doesn't,但它更简单,因为结果只需要一行和一列。您的问题更复杂,因此查询更复杂,至少可以这么说。这是疯狂的方法:

; 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)回答了这个问题:
Why can't I use a CASE statement to see if a column exists and not SELECT from it?

【讨论】:

  • 这很酷!有没有办法让这个工作与多个列一起工作,但不做更多的连接?
  • 感谢您的快速回复!不幸的是,我使用的是 SAP Hana,它没有 CROSS APPLY。你能想出一个替代的解决方案吗?我找到了这个stackoverflow.com/questions/26020765/…,但我不确定它是否会起作用。
  • @surjikal 我看不出这个答案会如何工作。我对 SAP Hana 不熟悉,所以无法回答。您使用的是哪个版本,它背后的 DBMS 是什么? DBMS 是称为 SAP Hana 还是与另一个 dbms 通信。如果您能找到您产品的 SQL 文档,那将会有所帮助。一些数据库有 CROSS/OUTER APPLY,其他有类似的 LATERAL 连接。您还可以发布另一个带有 SAP Hana 标记的问题(在此处或最好在 dba.stackexchange.com 上)。如果需要,请附上此问题的链接!
  • @ypercubeᵀᴹ 。 . .这是非常聪明的,使用范围规则来处理不存在的列。赞一个!
  • SAP Hana 是 DBMS,它似乎对 SQL 扩展没有太多支持。它有大多数常规连接,但不幸的是没有 CROSS/OUTER APPLY 或 LATERAL 连接。文档在这里:help-legacy.sap.com/saphelp_hanaplatform/helpdata/en/20/…
【解决方案3】:

您可以使用动态 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;

【讨论】:

    猜你喜欢
    • 2017-09-20
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-24
    相关资源
    最近更新 更多