jam*_*art 3 sql sql-server sql-server-2012
我必须从两个表中的每一个中删除一行,它们由一个 ID 链接但没有正确的 PK - FK 关系(这个数据库没有外键!)
这些表具有假定的 1-1 关系。我不知道为什么它们不只是放在同一张桌子上,但我不能随意更改它。
PersonId | Name | OwnsMonkey
----------------------------
1 Jim true
2 Jim false
3 Gaz true
Run Code Online (Sandbox Code Playgroud)
PersonId | FurtherInfo
-----------------------------
1 Hates his monkey
2 Wants a monkey
3 Loves his monkey
Run Code Online (Sandbox Code Playgroud)
要决定删除什么,我必须找到一个用户名以及他们是否拥有一只猴子:
Select PersonId from People where Name = 'Jim' and OwnsMonkey = 'false'
Run Code Online (Sandbox Code Playgroud)
所以我使用这个想法做两个单独的陈述,Info首先删除,然后从People
delete from Info where PersonId = (Select PersonId from People where Name = 'Jim' and OwnsMonkey = 'false');
delete from People where PersonId = (Select PersonId from People where Name = 'Jim' and OwnsMonkey = 'false');
Run Code Online (Sandbox Code Playgroud)
我在 StackOverflow 上找到了一个有希望的答案
delete a.*, b.*
from People a
inner join Info b
where a.People = b.Info
and a.PersonId =
(Select PersonId from People where Name = 'Jim' and OwnsMonkey = 'false')
Run Code Online (Sandbox Code Playgroud)
但是它在 Sql Server (2012) 中给出了语法错误,我也尝试了没有别名的情况,但似乎不可能同时删除两个表
我可以在一个语句中删除两个表中的条目吗?
不能。一条语句只能从 MS SQL Server 中的一个表中删除行。
您所指的答案是关于 MySQL 的,而 MySQL 确实允许使用一条语句从多个表中删除,如MySQL 文档中所示。MS SQL Server 不支持这一点,可以在docs 中看到。DELETE在 SQL Server的语句中没有包含多个表的语法。如果您尝试从视图而不是表中删除,也有一个限制:
table_or_view_name 引用的视图必须是可更新的,并且在视图定义的 FROM 子句中引用了一个基表。
我希望避免在偶然情况下出现两个单独的语句,第二个语句由于任何原因都不起作用,中断了 - 真的是并发,我猜 TRY/CATCH 会很好地工作。
这就是交易的目的。您可以在一个事务中放置多个语句,它们要么全部成功,要么全部失败。要么全有,要么全无。
在您的情况下,您不仅可以,而且应该将两个DELETE语句放在一个事务中。
TRY/CATCH 有助于以更可控的方式处理可能的错误,但主要概念是“事务”。
BEGIN TRANSACTION
delete from Info where PersonId = (Select PersonId from People where Name = 'Jim' and OwnsMonkey = 'false');
delete from People where PersonId = (Select PersonId from People where Name = 'Jim' and OwnsMonkey = 'false');
COMMIT
Run Code Online (Sandbox Code Playgroud)
我强烈建议阅读Erland Sommarskog 撰写的一篇很棒的文章SQL Server 中的错误和事务处理。
如果你想变得棘手,像这样:
WITH
CTE
AS
(
SELECT
Info.PersonId AS ID1, People.PersonId AS ID2
FROM
Info
INNER JOIN People ON Info.PersonId = People.PersonId
)
DELETE FROM CTE
WHERE ID1 = 1;
Run Code Online (Sandbox Code Playgroud)
你会得到一个错误:
视图或函数“CTE”不可更新,因为修改会影响多个基表。
或者像这样:
WITH
CTE
AS
(
SELECT
PersonId
FROM Info
UNION ALL
SELECT
PersonId
FROM People
)
DELETE FROM CTE
WHERE PersonId = 1;
Run Code Online (Sandbox Code Playgroud)
你会得到另一个错误:
视图“CTE”不可更新,因为定义包含 UNION 运算符。
| 归档时间: |
|
| 查看次数: |
92 次 |
| 最近记录: |