【问题标题】:SQL UPDATE based on COUNT基于 COUNT 的 SQL UPDATE
【发布时间】:2017-01-24 08:06:05
【问题描述】:

我有一个如下所示的表格

ID   |   action   |  flag
1    |   A        |  1
1    |   A        |  1
1    |   B        |  1
2    |   A        |  1
2    |   A        |  1
2    |   B        |  1
2    |   B        |  1

我想要执行以下操作:如果对于相同的 IDaction 列中的值 B 出现的次数多于 1时间,那么我想将这个IDflag列设置为0

结果应该是这样的:

ID   |   action   |  flag
1    |   A        |  1
1    |   A        |  1
1    |   B        |  1
2    |   A        |  0
2    |   A        |  0
2    |   B        |  0
2    |   B        |  0

我知道两种方法:

  • 使用子查询:但是我不想使用子查询,因为我处理的是大表,子查询会降低性能
  • 使用临时查找表:我创建​​了一个临时查找表,其中存储了 action 中具有值 BIDs列超过 1 次,然后我 join 与原始表的临时表找到我将为其设置 flagIDs0

除了上述两种方法之外,还有其他选择吗?理想情况下在一个查询中(没有子查询和临时查找表)。我在想JOIN 之类的东西,其中JOIN 子句包含GROUP BYHAVING 之类的东西,但直到现在我才成功..

【问题讨论】:

  • 对于ID=1A 也不止一次出现。为什么只需要更新ID=2
  • “子查询会降低性能” - 这句话并不总是正确的.....
  • 因为条件是,B 应该出现多次。
  • @AndyKorneyev,但肯定比创建查找表一次更糟糕,因为子查询需要为每一行执行一次。
  • @beta “因为子查询需要为每一行执行一次。” - 这个语句并不总是正确的,例如像update t set.... where ID in (subquery)这样的子查询(或查询in answers) 将只执行一次整个查询。

标签: sql-server join sql-update aggregate


【解决方案1】:

这样的东西应该适合你:

UPDATE t
SET flag = 0
FROM Table t
INNER JOIN 
(
    SELECT Id
    FROM Table
    WHERE action = 'B'
    GROUP BY Id
    HAVING COUNT(*) > 1
) d ON t.Id = d.Id

【讨论】:

  • 谢谢,但这不是子查询吗?这比临时查找表有更好的性能吗?
  • @beta 是的,它是一个子查询,但它与任何东西都没有相关。意思是,数据库真的只需要执行一次。
  • 称为派生表。因为它在from 子句中,所以它只会执行一次,与set 子句中的子查询相反,它将为更新中的每一行执行一次。
  • 好的,所以不相关的子查询只执行一次。但JOIN 可能很广泛?
  • 你是说贵?如果您有适当的索引,则不会。
【解决方案2】:

将原始表更新连接到使用聚合来识别候选 ID 值的子查询是我想到的最快方法:

UPDATE t1
SET flag = 0
FROM yourTable t1
INNER JOIN
(
    SELECT ID
    FROM yourTable
    GROUP BY ID
    HAVING SUM(CASE WHEN action = 'B' THEN 1 ELSE 0 END) > 1
) t2
    ON t1.ID = t2.ID

请注意,此子查询不相关,这意味着 SQL Server 只会对整个 UPDATE 执行一次。因此,这并没有你想象的那么大。

如果您创建了一个正式的查找表,理论上您可以为连接列添加索引,这可能会使UPDATE 更快。但是创建 维护查找表是一件麻烦事。在生产环境中,我更希望使用单个查询来进行更新。

【讨论】:

  • 这种性能表现如何?它比事先创建一个临时查找表更好/等于/更差吗?谢谢。编辑:感谢关于子查询不相关的澄清。
  • 'COUNT(CASE WHEN action = 'B' THEN 1 ELSE 0 END)' 我认为即使'B'不存在它也会返回相同的计数,'0'和'1'都会视为计数。
  • @AbdulRasheed 你说得对...改成SUM(),谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多