SQL和运算符工作不正常

SQL和运算符工作不正常,sql,Sql,我有以下两张桌子 地块表 Blockid ParcelNo storPri ======= ======== ======= 52000105 3 State 52000105 4 Private 52000105 5 State 动作表 Blockid ParcelNo ActionTaken ======= ======== =========== 52000105 3 Received 52000105 3 Send

我有以下两张桌子

地块表

Blockid ParcelNo storPri
======= ======== =======
52000105   3      State
52000105   4      Private
52000105   5      State
动作表

Blockid ParcelNo ActionTaken
======= ======== ===========
52000105   3      Received
52000105   3      Send to Computer
52000105   4      Received
52000105   5      Received
我想查找已接收的记录,但不想查找发送到计算机的记录

这是我的问题

select 
    l.blockid, l.parcelno 
from 
    landparcels l 
left join 
    actions ac on l.blockid = ac.blockid and l.parcelno = ac.parcelno 
where 
    ac.actiontaken = 'Received' 
    and ac.actiontaken <> 'Send to Computer'  
    and ac.blockid = 52000105 
我要4号和5号包裹

select a.blockid
      ,a.parcelno
  from landparcels a
  join actions     b on(a.blockid = b.blockid and a.parcelno = b.parcelno)
 where b.action_taken in('Received', 'Send to Computer')
   and a.blockid = 52000105
 group 
    by a.blockid
      ,a.parcelno
having count(*) = 1
   and min(b.action_taken) = 'Received';
或者一些不太新奇的东西,可以扩展到寻找二取一的特例之外:

select a.blockid
      ,a.parcelno
  from landparcels a
  join actions     b on(a.blockid = b.blockid and a.parcelno = b.parcelno)
 where b.blockid = 52000105
   and b.action_taken = 'Received'
   and not exists(
      select 'x'
        from actions x
       where x.action_taken = 'Send to Computer'
         and b.blockid  = x.blockid 
         and b.parcelno = x.parcelno
   );
我刚刚意识到,考虑到您的需求,您不需要加入landparcels,但我保留原样,以防您的实际需求需要来自该表的数据

更新
添加了blockid筛选器

如果您的数据库支持
where
子句中的
元组
,请重试

select *
from landparcels
where (blockid, parcelno) in
(
    select blockid, parcelno
    from actions
    where actiontaken = 'Received'
)
and  (blockid, parcelno) not in
(
    select blockid, parcelno
    from actions
    where actiontaken = 'Send to Computer'
)
编辑以响应marc_s:否则,请尝试此版本,我认为它是ANSI版本

select *
from landparcels as p
where exists
(
    select 1
    from actions
    where actiontaken = 'Received'
    and blockid = p.blockid
    and parcelno = p.parcelno
)
and not exists
(
    select 1
    from actions
    where actiontaken = 'Send to Computer'
    and blockid = p.blockid
    and parcelno = p.parcelno
)

您没有说您使用的是什么数据库系统-但在SQL Server上,您可以在此处使用此查询:

SELECT 
    lp.*
FROM 
    dbo.LandParcels lp
WHERE
    EXISTS(SELECT * FROM abo.ActionTaken a 
           WHERE a.blockid = lp.blockid 
             AND a.parcelno = lp.parcelno 
             AND a.ActionTaken = 'Received')
    AND NOT EXISTS(SELECT * FROM dbo.ActionTaken a 
                   WHERE a.blockid = lp.blockid 
                     AND a.parcelno = lp.parcelno 
                     AND a.ActionTaken = 'Send to Computer')
这将导致以下输出:

blockid parcelno    storePrio
52000105       4          Private
52000105       5          State

请注意,在任何常用的数据库产品中,您都不太可能在AND运算符中找到一个简单的错误。这里的问题不是数据库引擎没有生成正确的结果,而是您不了解AND运算符的作用

查看您的状况
ac.actiontake='Received'和ac.actiontake'Send to Computer'
。接下来,引擎将检查输出中的每一行,并确定它是否满足指定的条件。那么,对于第一行,采取的行动是“收到”的吗?对采取的行动不是“发送到计算机”也是真的吗?当然因此,该行符合条件

事实上,任何ActionTaked为“Received”的行都将符合条件,因为根据定义,该行的ActionTaked也不是“Send to Computer”

有很多方法可以得到你想要的答案。这是我最喜欢的一个:

SELECT DISTINCT a.blockid, a.parcelno FROM actions a 
WHERE a.blockid = 52000105 AND a.actiontaken = 'Received' AND NOT EXISTS
   (SELECT * FROM actions a2 WHERE a2.blockid = a.blockid AND 
                                   a2.parcelNo = a.parcelNo AND 
                                   a2.actiontaken = 'Send to Computer')

@Kirakun'row constructors'答案的另一个变体仍然是ISO/ANSI语法,但SQL Server确实支持这一点:

SELECT blockid, parcelno
  FROM landparcels
INTERSECT 
SELECT blockid, parcelno
  FROM actions
 WHERE actiontaken = 'Received'
EXCEPT 
SELECT blockid, parcelno
  FROM actions
 WHERE actiontaken = 'Send to Computer';

规范化您的操作表。@Mchl,您为什么说它没有规范化?您使用的是什么数据库??该数据库的哪个版本???您的第一个解决方案不太正确,因为OP没有说明没有第三个ActionTaked值,使得子句
having count(*)=1
不正确。无法按blockid=52000105Ah进行筛选。。。我的错误。我没有看到where子句。无论如何,您的第一个解决方案似乎过于复杂,不是吗?但是您的第二个解决方案更干净(忽略连接的额外部分,您在回答中也提到了这一点)。这在所有数据库系统中都不起作用,例如,在SQL Server中,这不起作用…FWIW您的原始查询是有效的ISO/ANSI完整SQL-92语法,称为“行构造函数”。很有趣。我想微软对开放标准从来都不太热衷。廉价镜头:)
SELECT DISTINCT a.blockid, a.parcelno FROM actions a 
WHERE a.blockid = 52000105 AND a.actiontaken = 'Received' AND NOT EXISTS
   (SELECT * FROM actions a2 WHERE a2.blockid = a.blockid AND 
                                   a2.parcelNo = a.parcelNo AND 
                                   a2.actiontaken = 'Send to Computer')
SELECT blockid, parcelno
  FROM landparcels
INTERSECT 
SELECT blockid, parcelno
  FROM actions
 WHERE actiontaken = 'Received'
EXCEPT 
SELECT blockid, parcelno
  FROM actions
 WHERE actiontaken = 'Send to Computer';