risposta-alla-domanda-sullo-sviluppo-web-bd.com

Selezionare columnValue se la colonna esiste altrimenti null

Mi chiedo se posso selezionare il valore di una colonna se la colonna esiste e selezionare null altrimenti. In altre parole, vorrei "sollevare" l'istruzione select per gestire il caso quando la colonna non esiste.

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

Nota, sono nel mezzo per consolidare il mio modello di dati e il design. Spero di escludere questa logica nelle prossime settimane, ma mi piacerebbe davvero andare oltre questo problema proprio perché la correzione del modello di dati è uno sforzo che richiede più tempo di quello che vorrei affrontare ora.

Inoltre, vorrei poterlo fare in una sola query. Quindi non sto cercando una risposta come

controlla prima quali colonne sono presenti nella tua query secondaria. Quindi modificare la query per gestire in modo appropriato le colonne nella query secondaria.

36
Steven Wexler

Non puoi farlo con una semplice istruzione SQL. Una query SQL non verrà compilata a meno che non esistano tutti i riferimenti di tabella e colonna nella tabella.

Puoi farlo con SQL dinamico se la "sottoquery" è un riferimento di tabella o una vista.

In SQL dinamico, faresti qualcosa del tipo:

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;

Per una sottoquery effettiva, è possibile approssimare la stessa cosa verificando se la sottoquery ha restituito qualcosa con quel nome di colonna. Un metodo per questo è quello di eseguire la query: select top 0 * into #temp from (<subquery>) s e quindi controllare le colonne in #temp.

30
Gordon Linoff

Come altri hanno già suggerito, l'approccio sano è quello di avere domande che soddisfino il design del tuo tavolo.

Esiste un approccio piuttosto esotico per ottenere ciò che si desidera in SQL (puro, non dinamico). Un problema simile è stato riscontrato su DBA.SE: Come selezionare righe specifiche se esiste una colonna o tutte le righe se una colonna non lo fa ma era più semplice in quanto solo una riga e una colonna erano richieste come risultato . Il tuo problema è più complesso, quindi la query è più complicata, per non dire altro. Ecco, l'approccio folle:

; 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 ;

Presuppone inoltre che uniqueId sia univoco nel set di risultati della sottoquery.

Testato su SQL-Fiddle


E un metodo più semplice che ha l'ulteriore vantaggio che consente a più di una colonna con una sola subquery:

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 ;

La domanda è stata posta anche su DBA.SE ed è stata risolta da @ Andriy M (usando CROSS APPLY anche!) e Michael Ericsson (usando XML):
Perché non posso usare un'istruzione CASE per vedere se esiste una colonna e non SELEZIONARE da essa?

18
ypercubeᵀᴹ