在where条件下使用CASE WHEN

时间:2012-04-30 18:41:00

标签: sql sql-server

我想知道是否有人可以帮助我为以下逻辑编写一些代码。

我们有一张桌子

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

问题:

我需要选择以下条件失败的所有行:

  • id = lang(即1或2)
  • lang = 1当letter ='e'或lang = 2时letter = 2

我知道我可以硬编码。另外我想在一个查询中执行此操作。

请帮忙

4 个答案:

答案 0 :(得分:3)

WHERE NOT
(
    id = lang
    AND
    (
        (lang = 1 AND letter = 'e')
        OR (lang = 2 AND letter = '2')
    )
)

答案 1 :(得分:1)

select * from table
where id <> lang and
(lang<>1 and letter <> 'e' or
lang<>2 and letter <> '2')

假设您的意思是希望所有这些条件均为假的数据。

答案 2 :(得分:0)

我认为这是您要排除符合该标准的记录:

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

要获取记录,只需删除NOT

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

答案 3 :(得分:-1)

这里的想法是有三个业务规则可以实现为三个不同的元组约束(即表中的每一行都不是假的):

  1. idlang必须相等(问问题,为什么不将其作为计算列?)。

  2. 如果letter'E',那么lang必须为1(我认为您的问题中有一个拼写错误,而您说的是'e' 'E')。

  3. 如果letter'F',那么lang必须为2(我认为您的问题中有一个拼写错误,而您说的是2 'F')。

  4. 对于任何其他数据(例如,当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's和double-negative),例如

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

    从逻辑上讲,对于优化器来说这应该更好,因为对于上面的矛盾,每个析取成员必须是假的(换句话说,它只需要一个OR'ed子句为真,数据被认为是'坏')。在实践中(理论上?),优化器应该能够无论如何都能执行这样的重写!

    P.S。空值对逻辑有害 - 避免它们!


    这是我的测试代码,包含样本数据:

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