在SQL Server中使用子查询更新查询


80

我有一个简单的表结构,如下所示:

tempData

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║    80 ║
║ Ravi     ║    85 ║
║ Sanjay   ║    90 ║
╚══════════╩═══════╝

而且我还有另一个表名称,像tempDataView这样

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Ravi     ║       ║
║ Ravi     ║       ║
║ Sanjay   ║       ║
╚══════════╩═══════╝

我想更新表tempDataView,通过设置标志 根据tempDataView -名称相比的TempData -名称

是的,让我向您展示我尝试过的方法,我尝试使用Cursor解决此问题,并且完美解决了问题,但是我正在寻找使用Subquery解决问题的方法

这里是:

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

实际上,这就像我使用Subquery解决它的作业一样。

Answers:


176

您甚至可以在UPDATE语句上连接两个表,

UPDATE  a
SET     a.marks = b.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

为了提高性能,请在两个表上都定义一个INDEXon列marks

使用 SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )

1
这是正确的。但请建议我使用子查询执行此操作的任何方法。
Narendra Pal

1
更新的答案subquery,但我宁愿使用JOINSUBQUERY
John Woo

1
为什么要INDEXmarks列上定义一个?应该不在Name列上吗?
lindelof

1
发生错误:子查询返回的值超过1。当子查询遵循=,!=,<,<=,>,> =或将子查询用作表达式时,不允许这样做。
Pradip

1
单独尝试子查询并对其进行调整,直到仅获得1个结果。可能更改SELECTSELECT TOP 1
vahanpwns,2016年

33

因为您只是在学习,所以我建议您练习将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用作游乐场


5
是正确的学习方式。+1表示学习方式。谢谢
Narendra Pal

2

在我的示例中,我找到了解决方案,因为我在更新和子查询上存在相同的问题:

UPDATE
    A
SET
    A.ValueToChange = B.NewValue
FROM
    (
        Select * From C
    ) B
Where 
    A.Id = B.Id

1
感谢您的回答!为了帮助其他人阅读本文,您是否可以快速添加有关此代码为何解决问题的解释?
RedBassett

0

该线程的标题询问如何在更新中使用子查询。这是一个例子:

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(*)没有分组依据来知道要计数的内容。
paqogomez

@paqogomez只需尝试一下-在其中有任何记录的任何表上。例如。从EventLog中选择count(*),其中year = 2018
Graham Laight 18'Aug

因此,您只是在统计整个表。我支持我的
不赞成

那是您的特权,但是此线程的标题是“使用子查询更新查询”,而我的示例不言而喻地做到了这一点。仅供参考,我不算“整个表”-count(*)后跟“ where”子句-因此它计算满足“ where”条件的行。
Graham Laight

0

是带有一些示例的更新操作的很好的解释。尽管它是Postgres站点,但是SQL查询对于其他DB也有效。以下示例直观易懂。

-- 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 Server。
AntoineL
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.