【问题标题】:How to add and populate a sequence column to a link table如何向链接表添加和填充序列列
【发布时间】:2011-08-16 15:04:31
【问题描述】:

假设我有一张如下表:

create table filetype_filestatus (
  id             integer(11) not null auto_increment,
  file_type_id   integer(11) not null,
  file_status_id integer(11) not null,
)

我想像这样添加一个序列列:

alter table filetype_filestatus add column sequence integer(11) not null;
alter table filetype_filestatus add unique key idx1 (file_type_id, file_status_id, sequence);

现在我想添加列,这很简单,并用一些满足唯一键的默认值填充它。

sequence 列是为了让用户对特定file_type 的file_status 的显示任意排序。我不太关心初始顺序,因为可以在应用程序中修改它。

理想情况下,我会得到类似的结果:

FileType FileStatus Sequence
   1        1          1
   1        2          2
   1        3          3
   2        2          1
   2        2          2

我能想到的最好的是:

update filetype_filestatus set sequence = file_type_id * 1000 + file_status_id;

有更好的方法吗?

【问题讨论】:

  • 我对你的问题有点困惑。听起来您是在说 Sequence 的初始值并不重要。那么为什么不直接将其设置为1
  • 删除唯一键?那应该可以解决您的问题。即使有超过 1 条具有相同 file_type_id、file_status_id 和序列的记录 - 检索数据时会出现什么问题?
  • 以上所有cmets都是真的。我试图强制执行一些与应用程序开发人员将呈现给用户的内容相匹配的数据库约束。这是每个文件类型的屏幕,文件状态按显示的序列列号 1..n 排序。我不想手动订购它们,但我希望显示的序列列与应用程序将写入数据库的内容相匹配。

标签: mysql sql sequence composite-key


【解决方案1】:

嗯,我相信这应该可行:

UPDATE filetype_filestatus as a 
       SET sequence = (SELECT COALESCE(MAX(b.sequence), 0)  
                       FROM filetype_filestatus as b
                       WHERE b.file_type_id = a.file_type_id) + 1

WHERE sequence = 0

我建议将新列添加到表中,运行 alter table 语句(并获取默认值 0),运行更新语句,然后添加约束(好吧,你无论如何都必须)。任何被触及的东西都会更新为大于 0 的 sequence,因此它也可以安全地运行多次。


编辑:

正如@Dems 所指出的,子查询在更新之前运行,因此上述内容实际上不适用于此目的。它确实适用于单行插入(在这里根本没有帮助)。


编辑:

啊,你有一个id 列,这很好用(是的,我先测试了这个)。

UPDATE filetype_filestatus as a
       SET sequence = (SELECT COALESCE(COUNT(*), 0)
                       FROM filetype_filestatus as b
                       WHERE b.file_type_id = a.file_type_id
                       AND b.id < a.id) + 1
WHERE sequence = 0

不过,不知道对性能的影响。

【讨论】:

  • 你确定它会起作用吗?我期望更新的结果在同一个更新中传播到相关子查询中。更不用说缺乏保证更新行的顺序了。
  • Gnn,你是对的,它将它们都设置为相同的东西(即 1)。嗯...哦,最初的顺序似乎并不重要,所以我不在乎。
  • @X-Zero 我在 MySQL 中尝试了后一个语句,我得到“您不能在 FROM 子句中指定目标表 'a' 进行更新”。但是将“FROM filetype_filestatus as b”替换为“FROM (SELECT * FROM filetype_filestatus) as b”可以(参见:xaprb.com/blog/2006/06/23/…
  • @Dems 答案也有效,但我喜欢这个答案,因为它在一个更新声明语句中实现了我的理想化结果。
【解决方案2】:

如果您只需要“一些符合idx1 的值”,为什么不直接复制 id 字段呢?毕竟,它是独一无二的……

UPDATE
  filetype_filestatus
SET
  sequence = id;

编辑

如何根据对所问问题的 OP 更改来获取顺序值。

ROW_NUMBER() 在 MySQL 中不可用,而且我的理解是您也不能在源查询中使用正在更新的表。

create temporary table temp_filetype_filestatus (
  id             integer(11) not null auto_increment,
  file_type_id   integer(11) not null,
  file_status_id integer(11) not null,
  PRIMARY KEY (file_type_id, file_status_id)
)

INSERT INTO temp_filetype_filestatus (
  file_type_id,
  file_status_id
)
SELECT
  file_type_id,
  file_status_id
FROM
  filetype_filestatus
ORDER BY
  file_type_id,
  file_status_id

-- Update Option 1
------------------
UPDATE
  filetype_filestatus
SET
  sequence
  =
  (SELECT id FROM temp_filetype_filestatus
   WHERE file_type_id   = filetype_filestatus.file_type_id
     AND file_status_id = filetype_filestatus.file_status_id)
  -
  (SELECT id FROM temp_filetype_filestatus
   WHERE file_type_id   = filetype_filestatus.file_type_id
   ORDER BY file_status_id ASC LIMIT 1)
  +
  1

-- Update Option 2
------------------
UPDATE
  filetype_filestatus
SET
  sequence
  =
  (SELECT COUNT(*) FROM temp_filetype_filestatus
   WHERE file_type_id    = filetype_filestatus.file_type_id
     AND file_status_id <= filetype_filestatus.file_status_id)

【讨论】:

  • 见我上面的评论。这会起作用,实际上是比我的解决方案更简单的方法。但是,我希望能够在一组文件类型中实现 1..n 序列。
猜你喜欢
  • 2018-11-07
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2013-10-22
  • 2016-03-24
  • 2013-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多