SQL UPDATE基于COUNT

时间:2017-01-24 08:06:05

标签: sql-server join sql-update aggregate

我的表格如下所示

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

我想执行以下操作:如果对于相同的 ID 操作列中的值 B 将显示为 1以上时间,然后我想将此 ID 标志列设置为 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

我知道有两种方法可以做到这一点:

  • 使用子查询:但是,我不想使用子查询,因为我处理大型表,子查询会降低性能
  • 使用临时查找表:我创建​​了一个临时查找表,在其中我将 ID 存储在操作中,其值 B colum超过 1次,然后join临时表与原始表一起找到 ID ,我将为其设置 flag 0

除了上面解释的两个选项之外还有其他选择吗?理想情况下在一个查询中(没有子查询,没有临时查找表)。我在想JOIN之类的内容,其中JOIN子句包含GROUP BYHAVING之类的内容,但直到现在我还没有成功..

2 个答案:

答案 0 :(得分:3)

将原始表更新连接到使用聚合来标识候选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更快。但是创建维护查找表有一个麻烦。在制作中,我宁愿使用一个查询来进行更新。

答案 1 :(得分:3)

这样的事情对你有用:

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