Выберите columnValue, если столбец существует иначе null
Мне интересно, могу ли я выбрать значение столбца, если столбец существует, и просто выберите null в противном случае. Другими словами, я бы хотел "снять" оператор select, чтобы обработать случай, когда столбец не существует.
SELECT uniqueId
, columnTwo
, /*WHEN columnThree exists THEN columnThree ELSE NULL END*/ AS columnThree
FROM (subQuery) s
Обратите внимание: я нахожусь в середине, чтобы закрепить мою модель данных и дизайн. Я надеюсь исключить эту логику в ближайшие недели, но мне бы очень хотелось выйти за рамки этой проблемы, потому что исправление модели данных - это более трудоемкое занятие, чем я хотел бы сейчас решить.
Также обратите внимание: я хотел бы иметь возможность сделать это в одном запросе. Поэтому я не ищу ответа, например
сначала проверьте, какие столбцы находятся в вашем подзапросе. Затем измените свой запрос, чтобы соответствующим образом обрабатывать столбцы в вашем дополнительном запросе.
Ответы
Ответ 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;