Подтвердить что ты не робот

Выберите columnValue, если столбец существует иначе null

Мне интересно, могу ли я выбрать значение столбца, если столбец существует, и просто выберите null в противном случае. Другими словами, я бы хотел "снять" оператор select, чтобы обработать случай, когда столбец не существует.

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

Обратите внимание: я нахожусь в середине, чтобы закрепить мою модель данных и дизайн. Я надеюсь исключить эту логику в ближайшие недели, но мне бы очень хотелось выйти за рамки этой проблемы, потому что исправление модели данных - это более трудоемкое занятие, чем я хотел бы сейчас решить.

Также обратите внимание: я хотел бы иметь возможность сделать это в одном запросе. Поэтому я не ищу ответа, например

сначала проверьте, какие столбцы находятся в вашем подзапросе. Затем измените свой запрос, чтобы соответствующим образом обрабатывать столбцы в вашем дополнительном запросе.

4b9b3361

Ответ 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 '[email protected]+' s
';

exec sp_executesql @sql;

Для реального подзапроса вы можете приблизиться к одному и тому же, проверив, чтобы подзапрос возвращал что-то с этим именем столбца. Один из способов этого - запустить запрос: select top 0 * into #temp from (<subquery>) s, а затем проверить столбцы в #temp.

Ответ 2

Как уже предлагали другие, разумный подход состоит в том, чтобы иметь запросы, которые соответствуют дизайну вашей таблицы.

Существует довольно экзотический подход для достижения того, что вы хотите в (чистом, а не динамическом) 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, чтобы увидеть, существует ли столбец, а не SELECT из него?

Ответ 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;