2016-11-02 21 views
2

私はnote列のテーブルを持っていて、値は「開始」または「終了」です。そして、同じ値を持つことができる他の列がありますが、違いはその 'ノート'列にあります...SQLクエリが複雑すぎる

'メモ'が '開始'に設定されている行を選択する必要がありますが、同じ値を持つ行はなく、 'note'は 'End'に設定されています。申し訳ありませんが、説明するのは難しいです。私はいくつかの例を見せようとします。

Coll1 Coll2 Coll3 note 
----------------------------- 
a  a  a  Start 
a  a  a  End 
b  b  b  Start 
b  b  b  End 
c  c  c  Start <- I need select those rows 
-- There is no row with 'c c c End' combination in the table 
d  d  d  Start 
d  d  d  End 
e  e  e  Start <- I need select those rows 
-- There is no row with 'e e e End' combination in the table 

誰でも教えてください。

答えて

4

たぶん、このクエリは最適ではない

SELECT * 
    FROM tbl t1 
    WHERE t1.note = 'Start' AND NOT EXISTS (SELECT * 
              FROM tbl t2 
              WHERE t2.note = 'End' 
              AND t2.Coll1 = t1.Coll1 
              AND t2.Coll2 = t1.Coll1 
              AND t2.Coll3 = t1.Coll3) 

を使用しますが、このクエリは理解しやすいですしてみてください。

2

これはあなたのために機能しますか?

SELECT * 
FROM mytable t1 
LEFT JOIN mytable t2 ON 
    t1.Coll1 = t2.Coll1 AND 
    t1.Coll2 = t2.Coll2 AND 
    t1.Coll3 = t2.Coll3 AND 
    t2.note = 'End' 
WHERE t1.note = 'Start' AND t2.Coll1 IS NULL 
+0

なぜあなたは反結合パターンを提案しますか?このトリックは、 'EXISTS'と' IN'をうまく扱えない(弱い)DBMSで使われます。これは読みやすさの犠牲を払って行われます。オラクルはそのようなトリックは必要ありません。あなたの質問はできるだけ読みやすくしてください。データ*がセットに存在するかどうかを確認するには、* exists *または* in *を使用します。 –

+0

まず、私はこのプリミティブなクエリを考えています。あなたは多くの方法でそれをデザインすることができます。それは本当にあなたが2つのセットの相互作用を想像する方法です。誰かが1つのセットを見て、他のセットで一致するものがあるかどうかを調べることが好きです。私は、セットをマージし、データを見て、私が必要としない行を削除することを好む。第二に、私は 'EXISTS'サブクエリの' t1'を参照することでそれ以上の読み込みができないとは思いません。私は本当にしません。 –

2

最も簡単な方法は、レコードを集約し、グループのためのエンド・レコードがあるかどうかを確認する必要があります:あなたが好きなように

select col1, col2, col3 
from mytable 
group by col1, col2, col3 
having count(case when note = 'Start' then 1 end) = 1 
    and count(case when note = 'End' then 1 end) = 0; 

はこれを調整(例えばあなたは、いくつかの開始レコードと罰金であれば、それを作ります> = 1ではなく1)。

2

質問にCREATE TABLEステートメントとINSERTステートメントを含めると、より多くの回答が得られます。私はPostgreSQLを使用しています。オラクルは似ています。

create table test (
    col1 char(1) not null, 
    col2 char(1) not null, 
    col3 char(1) not null, 
    note varchar(10) not null 
    check (note in ('start', 'end')), 
    primary key (col1, col2, col3, note) 
); 

私はprimary key (col1, col2, col3, note)と仮定しています。 NULLの存在はこのアプローチを複雑にします。

insert into test values 
('a', 'a', 'a', 'start'), 
('a', 'a', 'a', 'end'), 
('b', 'b', 'b', 'start'), 
('b', 'b', 'b', 'end'), 
('c', 'c', 'c', 'start'), 
('d', 'd', 'd', 'start'), 
('d', 'd', 'd', 'end'), 
('e', 'e', 'e', 'start'); 

ここでは、一連の開始と終了のセットを取ることができます。左外部結合は、開始のすべての行を保持します。行末に欠落している行はNULLで埋められます。

with starts as (
    select * from test where note = 'start' 
), ends as (
    select * from test where note = 'end' 
) 
select s.* from starts s 
left outer join ends e 
    on e.col1 = s.col1 
and e.col2 = s.col2 
and e.col3 = s.col3 
where e.col1 is null 
    and e.col2 is null 
    and e.col3 is null 
    and e.note is null; 
0
SELECT coll1, coll2, coll3, count(*) 
FROM tbl 
Where note='start' 
GROUP BY coll1, coll2, coll3, 
HAVING count(*) < 2 
0

ここでは、すでに持っているものに追加する別のソリューションです:

WITH sample_data AS (SELECT 'a' Coll1, 'a' Coll2, 'a' Coll3, 'Start' note FROM dual UNION ALL 
        SELECT 'a' Coll1, 'a' Coll2, 'a' Coll3, 'End' note FROM dual UNION ALL 
        SELECT 'b' Coll1, 'b' Coll2, 'b' Coll3, 'Start' note FROM dual UNION ALL 
        SELECT 'b' Coll1, 'b' Coll2, 'b' Coll3, 'End' note FROM dual UNION ALL 
        SELECT 'c' Coll1, 'c' Coll2, 'c' Coll3, 'Start' note FROM dual UNION ALL 
        SELECT 'd' Coll1, 'd' Coll2, 'd' Coll3, 'Start' note FROM dual UNION ALL 
        SELECT 'd' Coll1, 'd' Coll2, 'd' Coll3, 'End' note FROM dual UNION ALL 
        SELECT 'e' Coll1, 'e' Coll2, 'e' Coll3, 'Start' note FROM dual) 
-- End of mimicking a table called "sample_data" with your data in it 
-- for use in the query below: 
SELECT coll1, 
     coll2, 
     coll3, 
     MAX(CASE WHEN note = 'Start' THEN note END) note 
FROM sample_data 
GROUP BY coll1, 
     coll2, 
     coll3 
HAVING MAX(CASE WHEN note = 'Start' THEN note END) = 'Start' 
AND  MAX(CASE WHEN note = 'End' THEN note END) IS NULL; 

COLL1 COLL2 COLL3 NOTE 
----- ----- ----- ----- 
e  e  e  Start 
c  c  c  Start 

それだけ(Surenameの答えでは2回のアクセスではなく)テーブルを介して1件のアクセスを持っていますしかし、どのソリューションがデータとテーブル構造に最も適しているかをテストする必要があります。完全性期すため

0

、それは好ましくはセットで考えるコメントで示唆されているために:

select col1, col2, col3 from mytable where note = 'Start' 
minus 
select col1, col2, col3 from mytable where note = 'End'; 
0

選択COL1、COL2、COL3、COL1によりTB1 グループから(注)をカウントし、col2に、col3というの uはそれを行うことができ、カウント(注)=も1

を持つ

選択* 'スタート'

TB1 ノート<> '終了' とノート=から
+0

@Llama、それが役に立ちましたか? –