web-dev-qa-db-ja.com

列が存在する場合はcolumnValueを選択し、そうでない場合はnull

列が存在する場合は列の値を選択でき、それ以外の場合はnullを選択できるかどうか疑問に思っています。つまり、列が存在しない場合を処理するために、selectステートメントを「リフト」したいのです。

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

注意してください、私は自分のデータモデルと設計を固めることに取り組んでいます。今後数週間でこのロジックを除外したいと思っていますが、データモデルの修正は今取り組むよりも時間がかかるため、この問題を乗り越えたいと思います。

また、これを1つのクエリで実行できるようにしたいと思います。だから私はのような答えを探していません

最初にサブクエリの列を確認してください。次に、クエリを変更して、サブクエリの列を適切に処理します。

36
Steven Wexler

簡単な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;
_

実際のサブクエリの場合、サブクエリがその列名で何かを返すかどうかを確認することで、同じことを近似できます。そのための1つの方法は、クエリselect top 0 * into #temp from (<subquery>) sを実行し、_#temp_の列をチェックすることです。

30
Gordon Linoff

他の人がすでに提案したように、正気なアプローチは、テーブルの設計を満たすクエリを持つことです。

ただし、(動的ではなく、純粋な)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 MCROSS APPLYも使用!)および Michael EricssonXMLを使用)で回答されました。
CASEステートメントを使用して、列が存在するかどうかを確認し、そこからSELECTできないのはなぜですか?

18
ypercubeᵀᴹ