SQL Server 多个列上的多个条件

pod7payv  于 2022-12-03  发布在  其他
关注(0)|答案(5)|浏览(224)

我有一张类似这样表

WO | PS | C
----------------
   12 | 1  | a
   12 | 2  | b
   12 | 2  | b
   12 | 2  | c
   13 | 1  | a

我想从WO列中查找值,其中PS值为1,C值为a AND PS值为2,C值为B因此,在一个列中,我需要有多个条件,我需要在WO列中查找它如果没有值与这四个条件中两个相匹配,我不想包含WO列
我试探着用条件:

WHERE PS = 1 AND C = a AND PS = 2 AND C = b

但是它不工作并且不具有如上所述的与WO柱的连接。
编辑:
我需要找到具有(PS = 1 AND C = a)的WO,同时它还具有(PS = 2 AND C = B)的行。
结果应该是:

WO | PS | C
----------------
   12 | 1  | a
   12 | 2  | b
   12 | 2  | b

如果任一行:(PS = 1且C = a)或(PS = 2且C = B)不存在,则不应返回任何内容。

ffx8fchx

ffx8fchx1#

其中(PS = 1且C = a)或(PS = 2且C = B)
试试这个条件

pes8fvy9

pes8fvy92#

根据我的理解,您需要两个IN子句或两个EXIST子句,如下所示:

SELECT DISTINCT wo, ps, c
FROM yourtable
WHERE wo IN 
  (SELECT wo FROM yourtable WHERE ps = 1 and c = 'a')
AND wo IN 
  (SELECT wo FROM yourtable WHERE ps = 2 and c = 'b');

这将产生以下结果:

WO | PS | C
----------------
   12 | 1  | a
   12 | 2  | b
   12 | 2  | c

请注意,在结果的最后一行中,列C的值为c,而不是您在问题中显示的B。我猜这是您在创建样本结果时的错误?
如果我理解你的问题不正确,请让我知道,并解释什么是错误的,然后我会审查它。
编辑:要创建与您的问题中显示的结果相同的结果,此查询将执行以下操作:

SELECT wo, ps, c
FROM yourtable
WHERE ps IN (1,2) AND c IN ('a','b')
AND wo IN 
  (SELECT wo FROM yourtable WHERE ps = 1 and c = 'a')
AND wo IN 
  (SELECT wo FROM yourtable WHERE ps = 2 and c = 'b');

但我真的不相信这是你要找的东西;)
试用:db<>fiddle

kognpnkq

kognpnkq3#

我认为您可以在这里使用一个 exists 标准来正确地过滤您的行,但我希望看到一个更广泛的样本数据集来确定。

select *  
from t
where ps in (1,2) and C in ('a','b')
and exists (
  select * from t t2 where t2.WO = t.WO
  and t2.PS != t.PS and t2.C != t.C
);
siv3szwd

siv3szwd4#

为了增加一个解决方案,您可以使用对表的单个引用来完成此操作,但这并不一定意味着它更高效。第一部分是基于所需的组合进行筛选:

DECLARE @T TABLE (WO INT, PS INT, C CHAR(1))
INSERT @T (WO, PS, C) 
VALUES (12, 1, 'a'), (12, 2, 'b'), (12, 2, 'b'), (12, 2, 'c'), (13, 1, 'a');

SELECT  *
FROM    @T AS t
WHERE   (t.PS = 1 AND t.C = 'a') 
OR      (t.PS = 2 AND t.C = 'B');

| 维修工单|PS系列|C语言|
| - -|- -|- -|
| 十二|一个|一种|
| 十二|2个|B|
| 十二|2个|B|
| 十三|一个|一种|
但是您希望排除WO 13,因为它没有这两种组合,因此理想情况下我们需要的是WS和C的非重复计数,以找到非重复计数为2的组合。您不能在窗口函数中直接执行COUNT(DISTINCT ..),但可以使用DENSE_RANK()间接执行此操作:

DECLARE @T TABLE (WO INT, PS INT, C CHAR(1))
INSERT INTO @T (WO, PS, C) 
VALUES (12, 1, 'a'), (12, 2, 'b'), (12, 2, 'b'), (12, 2, 'c'), (13, 1, 'a');

SELECT  *,
        CntDistinct = DENSE_RANK() OVER(PARTITION BY t.WO ORDER BY t.PS, t.C) + 
                        DENSE_RANK() OVER(PARTITION BY t.WO ORDER BY t.PS DESC, t.C DESC) - 1
FROM    @T AS t
WHERE   (t.PS = 1 AND t.C = 'a') 
OR      (t.PS = 2 AND t.C = 'B');

其给出:
| 维修工单|PS系列|C语言|计数相异|
| - -|- -|- -|- -|
| 十二|一个|一种|2个|
| 十二|2个|B| 2个|
| 十二|2个|B| 2个|
| 十三|一个|一种|一个|
然后,您可以将其放在子查询中,并只选择计数为2得行:

DECLARE @T TABLE (WO INT, PS INT, C CHAR(1))
INSERT INTO @T (WO, PS, C) 
VALUES (12, 1, 'a'), (12, 2, 'b'), (12, 2, 'b'), (12, 2, 'c'), (13, 1, 'a');

SELECT  t.WO, t.PS, t.C
FROM    (   SELECT  t.*,
                    CntDistinct = DENSE_RANK() OVER(PARTITION BY t.WO ORDER BY t.PS, t.C) + 
                                    DENSE_RANK() OVER(PARTITION BY t.WO ORDER BY t.PS DESC, t.C DESC) - 1
            FROM    @T AS t
            WHERE   (t.PS = 1 AND t.C = 'a') 
            OR      (t.PS = 2 AND t.C = 'B')
        ) AS t
WHERE   t.CntDistinct = 2;

最后,如果组合可能会更改,或者远远超过2个,您可能会发现构建一个组合表,您正在寻找一个更易于维护的解决方案:

DECLARE @T TABLE (WO INT, PS INT, C CHAR(1))
INSERT INTO @T (WO, PS, C) 
VALUES (12, 1, 'a'), (12, 2, 'b'), (12, 2, 'b'), (12, 2, 'c'), (13, 1, 'a');

DECLARE @Combinations TABLE (PS INT, C CHAR(1), PRIMARY KEY (PS, C));
INSERT @Combinations(PS, C)
VALUES (1, 'a'), (2, 'b');

SELECT  t.WO, t.PS, t.C
FROM    (   SELECT  t.*,
                    CntDistinct = DENSE_RANK() OVER(PARTITION BY t.WO ORDER BY t.PS, t.C) + 
                                    DENSE_RANK() OVER(PARTITION BY t.WO ORDER BY t.PS DESC, t.C DESC) - 1
            FROM    @T AS t
                    INNER JOIN @Combinations AS c
                        ON c.PS = t.PS
                        AND c.C = t.C
        ) AS t
WHERE   t.CntDistinct = (SELECT COUNT(*) FROM @Combinations);
vc6uscn9

vc6uscn95#

让我们来谈谈演示数据。您提供了一些有用的数据,帮助我们了解问题所在,但没有DDL。如果您提供类似于以下内容的演示数据,将使我们更容易了解问题:

DECLARE @table TABLE (WO INT, PS INT, C NVARCHAR(10))
INSERT INTO @table (WO, PS, C) VALUES
(12, 1, 'a'), (12, 2, 'b'),
(12, 2, 'b'), (12, 2, 'c'),
(13, 1, 'a')

现在来回答你的问题。在我看来,你只需要一个复合条件,其中一个条件需要评估为完全真。考虑一下:

SELECT *
  FROM @table
 WHERE (
            PS = 1 
        AND C = 'a'
       )
    OR (
            PS = 2 
        AND C = 'b'
       )

括在括号中的 predicate 在WHERE子句中作为一个整体进行计算。如果其中一个 predicate 为false,则整个 predicate 为false。如果任一组合的计算结果为true,则返回该行。

WO  PS  C
---------
12  1   a
12  2   b
12  2   b
13  1   a

这个结果集确实包括WO 13,因为根据您的定义,它应该在那里。我不知道是否有其他您想要评估的东西可能会排除它,但它确实有一个PS为1和一个C of a。
编辑:
如果问题如备注中所述,即单个WO必须包含两个,则答案可能是:
第一个

相关问题