【问题标题】:How to recalculate a field on GROUP如何重新计算 GROUP 上的字段
【发布时间】:2013-09-03 18:19:32
【问题描述】:

我有一张这样的桌子

f1|f2|fk
1 | 0|100
1 | 1|200
1 | 2|300
1 | 3|400
2 | 0|300
2 | 1|400
2 | 2|500

(f1,f2) 是 PK,fk 是外键。 fk 的值并不多,大约为 20。f2 永远不会超过 3。但是有很多 (f1,f2) 对。 (f1,fk)UNIQUE

现在,假设我们将 100 和 200 映射到 A,将 300 和 400 映射到 B,将 500 映射到 C—​​—这个映射是给定的。我们希望(f1_new,fk_mapped) 留下UNIQUE。到目前为止,这大致解决了

INSERT INTO mapped (f1_new,f2_new,fk_new)
SELECT f1, MIN(f2), CASE fk WHEN 100 THEN A WHEN 200 THEN A END AS fk
FROM origin
GROUP BY f1, fk

现在,问题是我们需要在映射表中保留 f2 值 0、1、2,所以这是想要的结果:

f1_new|f2_new|fk_mapped
1     | 0    |A
1     | 1    |B
2     | 0    |B
2     | 1    |C

我真的很想把它保留在 MySQL 中。

【问题讨论】:

  • 我很困惑 - 你说你想在映射表中保留 f2 的所有三个值,但你显示的所需结果没有 f2 == 2 的实例?
  • 他想分配f2 的新值,因此它们被保存在 0、1、2、... 的特定值 f1 的排序中。这是一个按 f1 排名的列。
  • 啊。知道了。我猜第一个示例表中的第四行应该有f2 == 3,那么。特别是如果 (f1, f2) 是主键。
  • 我修好了第一个表,确实是3。用f1 = entity_id,f2 = delta,f3 = target_id重写它真的更有帮助吗?我可以,但我不确定这有多大帮助。

标签: mysql sql select insert


【解决方案1】:

我认为应该这样做:

INSERT INTO mapped (f1_new, f2_new, fk_new)
SELECT f1_new, f2_new, fk_new from (
    SELECT f1_new, @f2 := if(f1_new = @prev_f1, @f2+1, 0) f2_new, fk_new, @prev_f1 := f1_new
    FROM (select f1 AS f1_new, CASE WHEN fk IN (100, 200) THEN 'A'
                                    WHEN fk in (300, 400) THEN 'B'
                                    WHEN fk = 500 THEN 'C'
                               END AS fk_new
          FROM origin
          GROUP BY f1_new, fk_new
          ORDER BY f1_new, fk_new) new,
         (SELECT @f2 := NULL, @prev_f1 := NULL) vars
    ) x

FIDDLE

【讨论】:

  • 我相信上述内容很棒,但“不可预测”您无法知道 @prev_f1 := 是否先触发。但是@f2 := if(f1_new = @prev_f1, @f2 + 1, 0) + LEAST(0, @prev_f1 := f1_new) 应该可以工作,因为+ 是从左到右的。来自How to Optimize Rank Data in MySQL 的想法
  • 另外,根据manual:如果您使用 GROUP BY,则输出行将根据 GROUP BY 列进行排序,就好像您对相同的列有一个 ORDER BY。
  • @chx 我已经多次看到并使用过它的变体。虽然可能无法保证,但实际上我认为它总是从左到右工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多