2012-04-30 19 views
1

誰かが次のロジックのコードを書くのを手助けできるかどうか疑問に思っていました。whereの条件でCASE WHENを使用する

  • ID = LANG(つまりそのいずれか:私は、次の条件が失敗したため、すべての行を選択する必要が

    :私たちはテーブル

    ---------------- 
    id, lang, letter 
    ---------------- 
    1 1  E 
    1 1  E 
    1 1  E 
    1 1  E 
    2 2  F 
    

    問題を抱えている

    1または2)

  • レター= 'e'の場合はlang = 1、レター= 2の場合はlang = 2

私はそれをハードコードすることができます。また、私はこれを1つのクエリでのみ行いたいと思います。

あなたはそれらの両方の条件が偽であるすべてのデータが欲しいわけ仮定

+2

あなたの条件には意味がありません。質問を修正してください – Icarus

答えて

0

私はこれは、あなたがその基準を満たすレコードを除外したいものだと思いますここで考えているのは、3つの異なるタプル制約として実装できる3つのビジネスルールがあることです(つまり、テーブルのすべての行でfalseではない)。

  1. idとは等しくなければなりません(なぜなら、計算列を作るのはなぜですか?)。

  2. letter'E'であれば、lang1でなければなりません(私はあなたが'e'代わりの'E'言ったあなたの質問にタイプミスがあると仮定します)。

  3. letter'F'であれば、lang2でなければなりません(私はあなたが2代わりの'F'言ったあなたの質問にタイプミスがあると仮定します)。

制約は、他のデータについて「言うことは何もありません。」(例えばletter'X'の場合)、これを通過することができます。

すべての3つの組の制約は、制約の検証クエリとして連言標準形で書くことができる。

SELECT * FROM T 
WHERE id = lang 
     AND (letter <> 'E' OR lang = 1) 
     AND (letter <> 'F' OR lang = 2) 

制約に違反するデータは、単に(擬似リレーショナル代数に)示すことができる:

T MINUS (constraint validation query) 
SQLで

SELECT * FROM T 
EXCEPT 
SELECT * FROM T 
WHERE id = lang 
     AND (letter <> 'E' OR lang = 1) 
     AND (letter <> 'F' OR lang = 2) 

できるようにするには良いです自分の選択したクエリが選択されたDBMSにグルーのように実行される場合に、述語を書き換えます!上記は例えば以下のように書き直すことができる。

SELECT * FROM T 
WHERE NOT (id = lang 
      AND (letter <> 'E' OR lang = 1) 
      AND (letter <> 'F' OR lang = 2)) 

書き直し法(De Morganと二重否定)を適用します。

SELECT * FROM T 
WHERE id <> lang 
     OR (letter = 'E' AND lang <> 1) 
     OR (letter = 'F' AND lang <> 2) 

が論理的に言えば、上記のために、すべての論理和メンバーが偽でなければならない矛盾するので、これは別の言い方をすれば(オプティマイザのために良いはずです、それはデータのみのために真であることが1つの論理和句を取ります「悪い」とみなされる)。実際には(理論的には?)、オプティマイザであれば、このような書き換えを実行する必要があります。

p.s. nullsは論理に悪いです - それらを避けてください!ここで


は、サンプルデータと私のテストコードです:

WITH Nums AS (SELECT * 
       FROM (VALUES (0), (1), (2)) AS T (c)), 
    Chars AS (SELECT * 
        FROM (VALUES ('E'), ('F'), ('X')) AS T (c)), 
    T AS (SELECT N1.c AS id, N2.c AS lang, 
        C1.c AS letter 
       FROM Nums AS N1, Nums AS N2, Chars AS C1) 

SELECT * FROM T 
EXCEPT 
SELECT * FROM T 
WHERE id = lang 
     AND (letter <> 'E' OR lang = 1) 
     AND (letter <> 'F' OR lang = 2); 
1
select * from table 
where id <> lang and 
(lang<>1 and letter <> 'e' or 
lang<>2 and letter <> '2') 

を助けてください。

SELECT * 
FROM #t 
WHERE 
(
    id = lang 
    AND 
    (
     (
      lang = 1 
      AND letter = 'E' 
     ) 
     OR 
     (
      lang = 2 
      AND letter = '2' 
     ) 
    ) 
) 
3
​​
-1

:ちょうどNOTそれを削除し、

create table #t 
(
    id int, 
    lang int, 
    letter varchar(1) 
) 

insert into #t values (1, 1, 'E') 
insert into #t values (1, 1, 'E') 
insert into #t values (1, 1, 'E') 
insert into #t values (1, 1, 'E') 
insert into #t values (2, 2, 'F') 
insert into #t values (1, 1, 'G') 
insert into #t values (1, 1, 'H') 
insert into #t values (1, 1, 'I') 
insert into #t values (1, 1, 'J') 
insert into #t values (2, 2, '2') 


SELECT * 
FROM #t 
WHERE NOT 
(
    id = lang 
    AND 
    (
     (
      lang = 1 
      AND letter = 'E' 
     ) 
     OR 
     (
      lang = 2 
      AND letter = '2' 
     ) 
    ) 
) 

drop table #t 

はそれでレコードを取得する: