在 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

然后请注意,我们有两个表别名 ab。使用这些别名,您可以轻松地生成 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 中使用子查询更新查询的主要内容,如果未能解决你的问题,请参考以下文章

Oracle - 子查询TOP - N

SQL嵌套SELECT语句的用法-

SQL 基础之子查询

sqlserver 表 无法更新和删除 子查询返回的值不止一个

如何在 SQL Server 中的 UPDATE 查询的子查询中引用表变量

SQL Server 触发器:子查询返回超过 1 个值