57

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

もちろん、たくさんの行と列を持つテーブルがあります:P 次のように見えるとしましょう:

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

ここで、これを組み合わせた高度な選択ステートメントを作成したいと思います(ここでは疑似SQLっぽい):

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 つの選択ステートメントを 1 つの優れた選択ステートメントに結合するにはどうすればよいでしょうか?

以下のように 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 ステートメントのコピーと組み合わせて、「ステータス」フィールドを「DELETED」のような文字列に変更したいと考えています。

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)
4

8 に答える 8

77

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

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 つの解決策は、テーブルから 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

于 2009-02-12T18:49:40.743 に答える
9

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

(異なるテーブルの列から値を選択する必要がある場合は、JOIN代わりに見てください...)

于 2009-02-12T18:45:44.047 に答える
6

入力していただきありがとうございます。ここで言及されていることを試してみましたが、これらは私が仕事をするようになった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'

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

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

于 2009-02-13T10:28:19.490 に答える
1
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 に対して作業しているのかわかりません。

于 2009-02-12T18:45:56.650 に答える
1

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

于 2009-02-12T18:46:30.957 に答える
1

選択にケースを使用し、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')
于 2009-02-12T18:49:55.580 に答える
1

それがあなたが探しているものだと思います:

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

、より効率的です。

于 2009-02-12T18:52:38.163 に答える