【问题标题】:How to avoid GROUP BY or DISTINCT in UPDATE如何在 UPDATE 中避免 GROUP BY 或 DISTINCT
【发布时间】:2020-03-26 07:43:30
【问题描述】:

我有一张这样的桌子

    A   B   C   D   E   F
00002471    Sd3a28d471  0   24.00   377.500000  1
00002471    Sd3a28d471  0   353.50  377.500000  1
00002471    Sd3a28d471  1   211.00  211.000000  1

00002471    Sd3a28e471  1   343.00  343.000000  1
00002471    Sd3a28e471  0   56.00   242.370000  1
00002471    Sd3a28e471  0   177.06  242.370000  1
00002471    Sd3a28e471  0   9.31    242.370000  1

00002471    Sd3a28f471  0   10.31   10.31   1
00002471    Sd3a28f471  1   10.31   10.31   1

通过对 A、B 和 C 列进行分组,我需要检查 E 中哪一个具有最低值,并将最低值行的 F 列更新为 1,将其余列更新为 0。如果值为同样,我需要将 F 列更新为 1,其中 C 为 1。我需要的输出如下

    A   B   C   D   E   F
00002471    Sd3a28d471  0   24.00   377.500000  0
00002471    Sd3a28d471  0   353.50  377.500000  0
00002471    Sd3a28d471  1   211.00  211.000000  1

00002471    Sd3a28e471  1   343.00  343.000000  0
00002471    Sd3a28e471  0   56.00   242.370000  1
00002471    Sd3a28e471  0   177.06  242.370000  1
00002471    Sd3a28e471  0   9.31    242.370000  1

00002471    Sd3a28f471  0   10.31   10.31   0
00002471    Sd3a28f471  1   10.31   10.31   1

我在下面的查询中试过这个

UPDATE T1
SET T1.F = CASE WHEN T1.E <= T2.E THEN 1 ELSE 0 END
--select t2.*
FROM
(SELECT DISTINCT A,B,C,D,E,F FROM #SalesOrder WHERE E IS NOT NULL) T1 
INNER JOIN 
(SELECT DISTINCT A,B,C,D,E,F FROM #SalesOrder WHERE E IS NOT NULL) T2                           
ON  T1.A    = T2.A
AND T1.B    = T2.B
--AND T1.C  = T2.C
WHERE T1.C = 1 AND T2.C = 0

但是这个查询会抛出一个错误

错误信息
消息 4418,第 16 级,状态 1,第 265 行
派生表“T1”不可更新,因为它包含聚合、DISTINCT 或 GROUP BY 子句、PIVOT 或 UNPIVOT 运算符。

@Suresh Gajera 我需要取 A、B、C 和 E 的不同值,在取不同的值之后会是这样的

A   B   C   E
00002471    Sd3a28d471  0   377.500000
00002471    Sd3a28d471  1   211.000000
00002471    Sd3a28e471  0   242.370000
00002471    Sd3a28e471  1   343.000000
00002471    Sd3a28f471  0   10.31   
00002471    Sd3a28f471  1   10.31

在此之后我需要根据 C 列比较 E 的值,在此第二行与第一行比较时最低,所以第二行应该是 1,第一行应该是 0...以同样的方式第三行和第四行应该更新..当涉及到第 5 行和第 6 行时,在这种情况下值相同,我需要将 F 列更新为 1,其中 C 为 1

【问题讨论】:

  • 为什么要避免抱怨?
  • 在更新语句中使用 group by 或 distinct 时出现错误,错误详情如下。消息 4418,级别 16,状态 1,行 265 派生表“T1”不可更新,因为它包含聚合,或 DISTINCT 或 GROUP BY 子句,或 PIVOT 或 UNPIVOT 运算符。
  • 请通过编辑将该错误消息和您尝试的查询添加到您的问题中
  • 你能帮我理解为什么 F 列中第 3 行的 value = 1 和第 4 行的 value = 0。没看懂逻辑。
  • 如果我正确理解了您的问题陈述,那么您只需将 A 和 B 分组。无需按 C 分组。这是我看到您的预期输出后的感受。

标签: sql sql-server azure-sql-server


【解决方案1】:

只有按 A 和 B(不包括 C)分组时,您的预期结果才有意义。
在这种情况下:

update t
set t.f = case when t.e = tt.mine then 1 else 0 end
from tablename t inner join (
  select a, b, min(e) mine
  from tablename   
  group by a, b
) tt 
on tt.a = t.a and tt.b = t.b

请参阅demo
或者使用CTE 和窗口函数MIN()

with cte as (
  select *, min(e) over (partition by a, b) mine
  from tablename 
)
update cte
set f = case when e = mine then 1 else 0 end

请参阅demo
结果:

>    A | B          |  C |   D | E      |  F
> ---: | :--------- | -: | --: | :----- | -:
> 2471 | Sd3a28d471 |  0 |  24 | 377.50 |  0
> 2471 | Sd3a28d471 |  0 | 353 | 377.50 |  0
> 2471 | Sd3a28d471 |  1 | 211 | 211.00 |  1
> 2471 | Sd3a28e471 |  1 | 343 | 343.00 |  0
> 2471 | Sd3a28e471 |  0 |  56 | 242.37 |  1
> 2471 | Sd3a28e471 |  0 | 177 | 242.37 |  1
> 2471 | Sd3a28e471 |  0 |   9 | 242.37 |  1

【讨论】:

  • 感谢您的帮助@forpas 在以上两个选项中,我应该根据性能选择哪一个?
  • 窗口函数通常在大型数据集中表现更好,所以我建议第二个查询。
  • 我刚试过你的查询,当值不相等时,它工作正常,但是当值相等时它不工作..@forpas
  • 正如您在演示中看到的,查询正在处理您的示例数据。那么问题出在哪里?
  • 通过对 A、B 和 C 列进行分组,我需要检查 E 中哪一个具有最低值,并将最低值行的 F 列更新为 1,其余列更新为 0。如果值相同,我需要将 F 列更新为 1,其中 C 为 1,但是通过此查询,它将 F 列更新为 1,其中 C 为 1,同时 C 为 0...@forpas
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 1970-01-01
  • 2016-03-08
相关资源
最近更新 更多