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