2013-06-06 3 views
22

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

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

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

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

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

+1

Почему вы пишете код, предполагающий, что ваша модель данных будет волей-неволей? Почему не код для существующих столбцов, и когда ColumnThree становится постоянным первоклассным гражданином в вашей модели данных, исправьте запрос? Также я настоятельно рекомендую не сообщать людям, что вы не ищете.Ваше ограничение, как указано, невозможно встретить, и вам нужно дать более вескую причину. В одном запросе очень мало смысла, если вы можете инкапсулировать вещи в хранимую процедуру. –

+0

@AaronBertrand Вы задали два вопроса, поэтому я обращусь к обоим. Во-первых, моя цель - как можно скорее отправить высококачественную функцию. Прямо сейчас мне нужны значения из 'ColumnThree', когда они существуют, чтобы моя функция работала правильно. Поэтому я собираюсь использовать этот столбец, когда он существует ... даже если решение не изящно. –

+6

@AaronBertrand Во-вторых, я ценю вашу рекомендацию, но с уважением не согласен. Я хочу четко выразить свои требования, чтобы пользователи могли сосредоточиться на том, чтобы предлагать решения, которые решают мою проблему, не теряя времени, написав ответы, которые, как я знаю, будут неудовлетворительными. Я думаю, что именно то, что не будет удовлетворительным ответом, поможет пользователям сосредоточиться на более эффективных решениях. –

ответ

18

Вы не можете сделать это с помощью простого оператора 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.

+0

Я так не думаю. Из любопытства, как мне это сделать с динамическим SQL? –

+0

Вы создаете свой оператор sql как строку, а затем используете команду exec для выполнения строкой, которую вы создали. – liebs19

+0

И из моего понимания динамического sql, не требуется ли два запроса? –

12

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

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

+1

Это довольно круто! Есть ли способ сделать эту работу с несколькими столбцами, но не делая больше объединений? – surjikal

+0

@surjikal см. Мое редактирование! –

+0

Спасибо за быстрый ответ! К сожалению, я использую SAP Hana, и у нее нет 'CROSS APPLY'. Можете ли вы придумать альтернативное решение? Я нашел этот https://stackoverflow.com/questions/26020765/sap-hana-alternative-for-cross-apply, но я не уверен, что он сработает. – surjikal

Смежные вопросы