在 Sql Server 中使用子查询更新查询
Posted
技术标签:
【中文标题】在 Sql Server 中使用子查询更新查询【英文标题】:Update query using Subquery in Sql Server 【发布时间】:2013-01-15 03:16:33 【问题描述】:我有一个像这样的简单表格结构:
表tempData
╔══════════╦═══════╗
║ NAME ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║ 80 ║
║ Ravi ║ 85 ║
║ Sanjay ║ 90 ║
╚══════════╩═══════╝
而且我还有另一个表名 tempDataView 像这样
╔══════════╦═══════╗
║ NAME ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║ ║
║ Narendra ║ ║
║ Narendra ║ ║
║ Narendra ║ ║
║ Ravi ║ ║
║ Ravi ║ ║
║ Sanjay ║ ║
╚══════════╩═══════╝
我想更新表格 tempDataView ,通过根据 tempDataView - Name 比较设置 Marks使用 tempData - 名称
是的,让我向您展示我的尝试,我尝试使用光标解决这个问题,并且完美解决,但我正在寻找使用 子查询
解决它的方法这里是:
Declare @name varchar(50),@marks varchar(50)
Declare @cursorInsert CURSOR
set @cursorInsert = CURSOR FOR
Select name,marks from tempData
OPEN @cursorInsert
FETCH NEXT FROM @cursorInsert
into @name,@marks
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE tempDataView set marks = @marks where name = @name
FETCH NEXT FROM @cursorInsert
INTO @name,@marks
END
CLOSE @cursorInsert
DEALLOCATE @cursorInsert
实际上,使用子查询解决它就像我的作业一样。
【问题讨论】:
【参考方案1】:您甚至可以在 UPDATE
语句中加入这两个表,
UPDATE a
SET a.marks = b.marks
FROM tempDataView a
INNER JOIN tempData b
ON a.Name = b.Name
SQLFiddle Demo
为了获得更快的性能,请在两个表的 marks
列上定义一个 INDEX
。
使用SUBQUERY
UPDATE tempDataView
SET marks =
(
SELECT marks
FROM tempData b
WHERE tempDataView.Name = b.Name
)
SQLFiddle Demo
【讨论】:
它是对的。但请建议我使用子查询来执行此操作。 用subquery
更新了答案,但我宁愿使用JOIN
而不是SUBQUERY
。
为什么要在marks
列上定义INDEX
?它不应该在Name
列上吗?
遇到错误:子查询返回的值超过 1 个。当子查询跟随 =、!=、、>= 或子查询用作表达式时,这是不允许的。
自行尝试子查询并调整它,直到只得到 1 个结果。大概把SELECT
改成SELECT TOP 1
【参考方案2】:
因为您只是在学习,我建议您练习将 SELECT 连接转换为 UPDATE 或 DELETE 连接。首先,我建议您生成一个连接这两个表的 SELECT 语句:
SELECT *
FROM tempDataView a
INNER JOIN tempData b
ON a.Name = b.Name
然后请注意,我们有两个表别名 a
和 b
。使用这些别名,您可以轻松地生成 UPDATE 语句来更新表 a 或 b。对于表 a,您有 JW 提供的答案。如果要更新b
,则声明为:
UPDATE b
SET b.marks = a.marks
FROM tempDataView a
INNER JOIN tempData b
ON a.Name = b.Name
现在,要将语句转换为 DELETE 语句,请使用相同的方法。下面的语句将只从a
中删除那些名称匹配的记录(保持 b 不变):
DELETE a
FROM tempDataView a
INNER JOIN tempData b
ON a.Name = b.Name
您可以将 JW 创建的 SQL Fiddle 用作游乐场
【讨论】:
正确的学习方式。 +1 展示学习方式。谢谢【参考方案3】:该主题的标题询问如何在更新中使用子查询。这是一个例子:
update [dbName].[dbo].[MyTable]
set MyColumn = 1
where
(
select count(*)
from [dbName].[dbo].[MyTable] mt2
where
mt2.ID > [dbName].[dbo].[MyTable].ID
and mt2.Category = [dbName].[dbo].[MyTable].Category
) > 0
【讨论】:
我不确定这将如何编译,count(*) 没有 group by 知道要计算什么。 @paqogomez 试一试 - 在任何包含任何记录的表上。例如。 从 EventLog 中选择 count(*),其中年份 = 2018 那么你只是在计算整个表。我支持我的反对票,这与问题无关(无论标题如何) 那是你的特权,但这个线程的标题是“使用子查询更新查询”,我的例子不言而喻就是这样做的。仅供参考,我不计算“整个表” - count(*) 后跟一个“where”子句 - 所以它计算满足“where”条件的行。【参考方案4】:Here 通过一些示例很好地解释了更新操作。虽然它是 Postgres 站点,但 SQL 查询对其他数据库也有效。 以下示例直观易懂。
-- Update contact names in an accounts table to match the currently assigned salesmen:
UPDATE accounts SET (contact_first_name, contact_last_name) =
(SELECT first_name, last_name FROM salesmen
WHERE salesmen.id = accounts.sales_id);
-- A similar result could be accomplished with a join:
UPDATE accounts SET contact_first_name = first_name,
contact_last_name = last_name
FROM salesmen WHERE salesmen.id = accounts.sales_id;
但是,如果 salesmen.id 不是唯一键,则第二个查询可能会产生意外结果,而如果有多个 id 匹配,则第一个查询肯定会引发错误。此外,如果没有匹配特定的 accounts.sales_id 条目,第一个查询会将相应的名称字段设置为 NULL,而第二个查询根本不会更新该行。
因此,对于给定的示例,最可靠的查询如下所示。
UPDATE tempDataView SET (marks) =
(SELECT marks FROM tempData
WHERE tempDataView.Name = tempData.Name);
【讨论】:
很遗憾,第一种形式在 MS SQL 服务器中不起作用。【参考方案5】:在我的示例中,我找到了解决方案,因为我在更新和子查询方面遇到了同样的问题:
UPDATE
A
SET
A.ValueToChange = B.NewValue
FROM
(
Select * From C
) B
Where
A.Id = B.Id
【讨论】:
感谢您的回答!为了帮助其他人阅读本文,您能否快速添加解释为什么此代码可以解决问题?以上是关于在 Sql Server 中使用子查询更新查询的主要内容,如果未能解决你的问题,请参考以下文章
sqlserver 表 无法更新和删除 子查询返回的值不止一个