我在 Informix 数据库中有一个表,假设它名为 store,看起来像:
序列号 | store_seq |
---|---|
381-15 | 82600 |
381-15 | 82610 |
381-15 | 82640 |
381-15 | 82650 |
381-15 | 82680 |
381-114-1 | 82690 |
我必须更新serial_num,以便数字像这样增量更新:
序列号 | store_seq |
---|---|
381-15-1 | 82600 |
381-15-2 | 82610 |
381-15-3 | 82640 |
381-15-4 | 82650 |
381-15-5 | 82680 |
381-114-1 | 82690 |
将评论转录到问题中:
我尝试创建一个过程:
CREATE PROCEDURE update_store()
DEFINE counter INTEGER;
DEFINE temp_serial_num CHAR(20);
FOREACH cur1 FOR
SELECT serial_num INTO temp_serial_num FROM store WHERE serial_num = '381-15'
LET counter = 0;
WHILE counter < (SELECT COUNT(*) FROM store WHERE serial_num = '381-15')
LET counter = counter + 1;
UPDATE store
SET serial_num = temp_serial_num || '-' || counter::CHAR
WHERE CURRENT OF cur1;
END WHILE;
END FOREACH;
END PROCEDURE;
所有 381-15 号码中的结果是 381-15-5。
注意:
serial_num
列是 CHAR(16) 列; store_seq
是一个 INTEGER 列。
修复注释中的代码与表的架构之间的一些名称不匹配后,我发现您的存储过程不会更改数据。然而,这部分是因为在附加新计数器之前,您没有使用 TRIM 删除
serial_num
中的尾随空白。如果 serial_num
列是 VARCHAR 而不是 CHAR,则 TRIM 就不是必需的,但除了稍微减慢速度之外,它不会有任何害处。
我在表中添加了 Informix SERIAL 列
rec_num
:
DROP TABLE IF EXISTS store;
CREATE TABLE store
(
recnum SERIAL(1000) NOT NULL PRIMARY KEY,
serial_num CHAR(16) NOT NULL,
store_seq INTEGER NOT NULL
);
INSERT INTO store VALUES(0, '381-15', '82600');
INSERT INTO store VALUES(0, '381-15', '82610');
INSERT INTO store VALUES(0, '381-15', '82640');
INSERT INTO store VALUES(0, '381-15', '82650');
INSERT INTO store VALUES(0, '381-15', '82680');
INSERT INTO store VALUES(0, '381-114-1', '82690');
修改后的程序将
serial_num
作为参数来修复:
DROP PROCEDURE IF EXISTS update_store;
CREATE PROCEDURE update_store(snum CHAR(16))
DEFINE counter INTEGER;
DEFINE temp_serial_num CHAR(20);
TRACE ON;
FOREACH cur1 FOR
SELECT serial_num INTO temp_serial_num FROM store WHERE serial_num = snum
LET counter = 0;
WHILE counter < (SELECT COUNT(*) FROM store WHERE serial_num = snum)
LET counter = counter + 1;
UPDATE store
SET serial_num = TRIM(temp_serial_num) || '-' || counter::CHAR
WHERE CURRENT OF cur1;
END WHILE;
END FOREACH;
END PROCEDURE;
运行时,我得到输出:
recnum | 序列号 | store_seq |
---|---|---|
1005 | 381-114-1 | 82690 |
1003 | 381-15-1 | 82650 |
1004 | 381-15-1 | 82680 |
1002 | 381-15-2 | 82640 |
1001 | 381-15-3 | 82610 |
1000 | 381-15-4 | 82600 |
这会更改表中的数据,但由于未应用排序,因此行不会按照
store_seq
值的顺序更新,这似乎是所需的结果。
重写的程序处理排序问题:
DROP PROCEDURE IF EXISTS update_store;
CREATE PROCEDURE update_store(snum CHAR(16))
DEFINE counter INTEGER;
DEFINE old_serial_num CHAR(20);
-- DEFINE new_serial_num CHAR(20);
DEFINE old_store_seq INTEGER;
-- TRACE ON;
LET counter = 0;
FOREACH cur1 FOR
SELECT serial_num, store_seq
INTO old_serial_num, old_store_seq
FROM store
WHERE serial_num = snum
ORDER BY serial_num, store_seq
LET counter = counter + 1;
-- LET new_serial_num = TRIM(old_serial_num) || '-' || counter;
UPDATE store
SET serial_num = TRIM(old_serial_num) || '-' || counter
WHERE serial_num = old_serial_num AND store_seq = old_store_seq;
END FOREACH;
END PROCEDURE;
new_serial_num
变量(和TRACE ON;
语句)帮助识别缺失的 TRIM 问题。
这会产生输出:
recnum | 序列号 | store_seq |
---|---|---|
1005 | 381-114-1 | 82690 |
1000 | 381-15-1 | 82600 |
1001 | 381-15-2 | 82610 |
1002 | 381-15-3 | 82640 |
1003 | 381-15-4 | 82650 |
1004 | 381-15-5 | 82680 |
当游标上有 ORDER BY 子句时,无法将
WHERE CURRENT OF cur1
子句应用于 UPDATE。这就是为什么处理过程会通过 serial_num
和 store_req
来识别要更新的行。