web-dev-qa-db-ja.com

2つの選択ステートメントを1つに結合するにはどうすればよいですか?

SQL構文に関しては、私は初心者です。

もちろん、行と列がたくさんあるテーブルがあります:P次のようになります。

      AAA BBB CCC DDD
-----------------------
Row1 | 1   A   D   X
Row2 | 2   B   C   X
Row3 | 3   C   D   Z

今、私はこれを私に与える高度な選択ステートメントを作成したい(ここでは擬似SQLish):

select 'Test1', * from TABLE Where CCC='D' AND DDD='X'
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X'

出力は次のようになります。

Test1, 1, A, D, X
Test2, 2, B, C, X

これらの2つのselectステートメントを1つのNice selectステートメントに結合するにはどうすればよいですか?

以下のようにSQLを複雑にするとうまくいきますか(自分のSQL文にexists文が含まれているため)?選択を組み合わせて、それをやや高度なSQLに適用する方法を知りたいだけです。

select 'Test1', * from TABLE Where CCC='D' AND DDD='X' AND exists(select ...)
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' AND exists(select ...)




REAL SQLステートメントは次のとおりです。

select Status, * from WorkItems t1
where  exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00'

結果が得られます。しかし、最後にANDが追加されたこのselectステートメントのコピーとそれを組み合わせて、「ステータス」フィールドを「削除済み」などの文字列で変更します。

select 'DELETED', * from WorkItems t1
where  exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
44
Wolf5

ここには2つの選択肢があります。 1つは、WHERE句の条件に基づいて 'Test1'または 'Test2'を設定し、それらを一緒にUNIONする2つの結果セットを持つことです。

select 
    'Test1', * 
from 
    TABLE 
Where 
    CCC='D' AND DDD='X' AND exists(select ...)
UNION
select 
    'Test2', * 
from 
    TABLE
Where
    CCC<>'D' AND DDD='X' AND exists(select ...)

TABLEを2回効果的にスキャン/シークするため、これは問題になる可能性があります。

他の解決策は、テーブルから1回選択し、TABLEの条件に基づいて「Test1」または「Test2」を設定することです。

select 
    case 
        when CCC='D' AND DDD='X' AND exists(select ...) then 'Test1'
        when CCC<>'D' AND DDD='X' AND exists(select ...) then 'Test2'
    end,
    * 
from 
    TABLE 
Where 
    (CCC='D' AND DDD='X' AND exists(select ...)) or
    (CCC<>'D' AND DDD='X' AND exists(select ...))

ここでのキャッチは、CASEステートメントとWHEREステートメントでフィルター条件を複製する必要があることです。

61
casperOne

それらが同じテーブルにある場合、 UNION があなたが探しているコマンドだと思います。

(異なるテーブルの列から値を選択する必要がある場合、代わりに JOIN を確認する必要があります...)

9
Tomas Aschan

入力いただきありがとうございます。ここで言及されているものを試してみましたが、これらは私が働いた2つです:

(
select 'OK', * from WorkItems t1
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00'
AND (BoolField05=1)
)
UNION
(
select 'DEL', * from WorkItems t1
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)
)

そして

select 
    case
        when
            (BoolField05=1)
    then 'OK'
    else 'DEL'
        end,
        *
from WorkItems t1
Where
            exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
            AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
            AND TimeStamp>'2009-02-12 18:00:00'

これらは最も効率的です(編集:2回目はテーブルを1回しかスキャンしないため)、、さらに効率的にすることが可能です ? (BoolField = 1)は実際には変数(dyn sql)であり、テーブルのwhereステートメントを含めることができます。

MS SQL 2005で実行しています。Quassnoiの例を試しましたが、期待どおりに動作しませんでした。

4
Wolf5

nionコマンドが必要なものです。 それがうまくいかない場合は、現在の環境を改善する必要があるかもしれません。

1
JB King

選択にケースを使用し、ORを閉じる場所で使用する

このようなもの、私はそれをテストしませんでしたが、うまくいくはずです、私は思う...

select case when CCC='D' then 'test1' else 'test2' end, *
from table
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X')
1
Fredou

私はあなたが探しているものだと思う:

SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*
FROM WorkItems t1
WHERE (TextField01, TimeStamp) IN(
  SELECT TextField01, MAX(TimeStamp)
  FROM WorkItems t2
  GROUP BY t2.TextField01
  )
AND TimeStamp > '2009-02-12 18:00:00'

OracleまたはMS SQL 2005以降を使用している場合は、次のことができます。

SELECT *
FROM (
  SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*,
     ROW_NUMBER() OVER (PARTITION BY TextField01 ORDER BY TimeStamp DESC) AS rn
  FROM WorkItems t1
) to
WHERE rn = 1

、より効率的です。

1
Quassnoi
select t1.* from 
(select * from TABLE Where CCC='D' AND DDD='X') as t1,
(select * from TABLE Where CCC<>'D' AND DDD='X') as t2

これを行う別の方法!

1
arthur bryant
select Status, * from WorkItems t1
where  exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00'

UNION

select 'DELETED', * from WorkItems t1
where  exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1) )
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00'
AND NOT (BoolField05=1)

おそらくそれでうまくいくでしょう。ただし、ここからテストすることはできません。また、どのバージョンのSQLを対象にしているのかわかりません。

1
Kezzer