2012-04-30 4 views
1

누군가 다음 논리에 대한 코드를 작성하는 데 도움이 될지 궁금합니다.어디에서 CASE WHEN을 사용합니까?

우리는 테이블을 가지고

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

문제 : 다음과 같은 조건이 실패하는 모든 행을 선택해야

:

  • ID = LANG (즉, 자사을 중 1 또는 2)
  • 문자 = 'e'인 경우 lang = 문자 또는 문자 2 인 경우 lang = 2

나는 하드 코딩 할 수 있음을 알고 있습니다. 또한 하나의 쿼리에서만 이것을하고 싶습니다.

당신은 당신이 그 조건이 모두 거짓 모든 데이터를 원하는 뜻 가정

+2

귀하의 조건이 이해가되지 않습니다. 질문을 수정하십시오. – Icarus

답변

0

나는이 해당 기준을 충족 레코드를 제외 할 것을 생각 여기에 세 개의 별개의 튜플 제약 조건으로 구현 될 수있는 세 가지 비즈니스 규칙이 있습니다 (즉, 테이블의 모든 행에 대해 false가 아님).

  1. id과 은 같아야합니다 (질문을하기, 왜 계산 열을 만들지 않겠습니까?). letter'E' 경우

  2. 다음 lang (난 당신이 'e' 대신 'E' 말했다 질문에 오타가 있다고 가정) 1해야합니다. letter'F' 경우

  3. 다음 lang (난 당신이 2 대신 'F' 말했다 질문에 오타가 있다고 가정) 2해야합니다.

제약은 다른 데이터에 대해 '할 말이 아무것도하지 않는다'(예를 들어 letter'X' 경우)이 통과 할 수 있습니다.

세 튜플 제약

는 제약 검증 쿼리로 결합하는 일반적인 형태로 쓸 수있다 :

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과 double negative).

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

가 논리적이 때문에 위의 모든 분리 된 회원이 (거짓 다른 방법을 넣어해야합니다 모순 할 수 최적화에 더해야한다, 말하기, 그것은 단지 데이터에 대한 사실 하나의 OR 연산 절을합니다 '나쁜'것으로 간주 됨). 실제로 (이론적으로) 옵티마 이저 과 같은 재 작성을 수행 할 수 있어야합니다!

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
WHERE NOT 
(
    id = lang 
    AND 
    (
     (lang = 1 AND letter = 'e') 
     OR (lang = 2 AND letter = '2') 
    ) 
) 
-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 

그와 레코드를 얻을 :

관련 문제