您好,我是小DAI,专注于数据库管理员相关的技术问答,请问有什么可以帮您?

修改表变量的内容

除了基于索引的表单元格赋值之外,SQLScript 还提供了额外的操作来直接修改表变量的内容,而无需将 语句的结果分配给新的表变量。这与 SQL 层无关,导致性能改进。另一方面,此类操作需要数据实现,这与声明逻辑相反。 备注对于所有位置表达式,有效值位于 1 到 2^31-1 的区间内。

将数据记录插入到表变量中

可以使用以下语法在表变量的特定位置插入新数据记录:

:.INSERT(( ])

从给定索引开始的位置处的所有现有数据记录都将移动到下一位置。如果索引大于原始表大小,则使用 NULL 值初始化插入记录和原始最后记录之间的记录。

示例代码CREATE TABLE TAB(K VARCHAR(20), V INT);INSERT INTO TAB VALUES('A', 7582);INSERT INTO TAB VALUES('B', 4730);INSERT INTO TAB VALUES('C', 1960);INSERT INTO TAB VALUES('A', 8650);INSERT INTO TAB VALUES('D', 1318);INSERT INTO TAB VALUES('C', 3836);INSERT INTO TAB VALUES('B', 8602);INSERT INTO TAB VALUES('C', 3257);CREATE PROCEDURE ADD_SUM(IN IT TAB, OUT OT TAB) ASBEGIN DECLARE IDX INT = 0; DECLARE K VARCHAR(20) = ''; DECLARE VSUM INT = 0; IF IS_EMPTY(:IT) THEN RETURN; END IF; OT = SELECT * FROM :IT ORDER BY K; WHILE :OT.K[IDX + 1] IS NOT NULL DO IDX = IDX + 1; IF :OT.K[IDX] <> K THEN IF K <> '' THEN :OT.INSERT(('Sum ' || K, VSUM), IDX); IDX = IDX + 1; END IF; :OT.INSERT(('Section ' || :OT.K[IDX], 0), IDX); IDX = IDX + 1; K = :OT.K[IDX]; VSUM = 0; END IF; VSUM = VSUM + :OT.V[IDX]; END WHILE; :OT.INSERT(('Sum ' || K, VSUM), IDX + 1);ENDCALL ADD_SUM(TAB, ?)K V------------------Section A 0 A 7.582A 8.650Sum A 16.232Section B 0 B 4.730B 8.602Sum B 13.332Section C 0 C 1.960C 3.836C 3.257Sum C 9.053Section D 0 D 1.318Sum D 1.318

如果未指定索引(位置),数据记录将附加到末尾。

示例代码CREATE TABLE SOURCE(K VARCHAR(20), PCT DECIMAL(5, 2), V DECIMAL(10, 2));CREATE TABLE TARGET(K VARCHAR(20), V DECIMAL(10, 2));INSERT INTO SOURCE VALUES ('A', 5.99, 734.42);INSERT INTO SOURCE VALUES ('A', 50.83, 422.26);INSERT INTO SOURCE VALUES ('B', 75.07, 362.53);INSERT INTO SOURCE VALUES ('C', 87.21, 134.53);INSERT INTO SOURCE VALUES ('C', 80.72, 2722.49);CREATE PROCEDURE SPLIT(IN IT SOURCE, OUT OT1 TARGET, OUT OT2 TARGET) ASBEGIN DECLARE IDX INT; DECLARE MAXIDX INT = RECORD_COUNT(:IT); FOR IDX IN 1..MAXIDX DO DECLARE V1 DECIMAL(10, 2) = :IT.V[IDX] * :IT.PCT[IDX] / 100; DECLARE V2 DECIMAL(10, 2) = :IT.V[IDX] - V1; :OT1.INSERT((:IT.K[IDX], V1)); :OT2.INSERT((:IT.K[IDX], V2)); END FOR;END;CALL SPLIT(SOURCE, ?, ?);OT1 OT2K V K V ------------------------A 43,99 A 690,43A 214,63 A 207,64B 272,15 B 90,38C 117,32 C 17,21C 2.197,59 C 524,9

还可以为一组有限的列提供值:

:.(,…, ).INSERT((,…, ), [  ])

备注省略的列的值是使用 NULL 值初始化的。

将表变量插入到其他表变量中

您可以通过单个操作将一个表变量的内容插入到另一个表变量中,而无需使用 SQL。 代码语法:[.()].INSERT(:[, ])

如果未指定位置,则值将附加到末尾。位置从 1 - NULL 开始,所有小于 1 的值均无效。如果未指定列列表,则表的所有列都是插入目标。

示例代码用法示例:tab_a.insert(:tab_b);:tab_a.(col1, COL2).insert(:tab_b);:tab_a.INSERT(:tab_b, 5);:tab_a.("a","b").insert(:tab_b, :index_to_insert);

根据列位置,将源表的哪个列插入到目标表的哪个列中进行映射。源表的列数必须与目标表的列数相同,或与列列表中的列数相同。

如果 SOURCE_TAB 具有列 (X, A, B, C) 且 TARGET_TAB 具有列 (A, B, C, D),则 :target_tab.insert(:source_tab) 会将 X 插入到 A 中,将 A 插入到 B,将 B 插入到 C 中,并将 C 插入到 D 中。

如果需要其他顺序,则必须在 TARGET_TAB 的列列表中指定列顺序。例如 :TARGET_TAB.(D, A, B, C).insert(:SOURCE_TAB) 会将 X 插入 D,将 A 插入到 A,将 B 插入到 C 中。

列的类型必须匹配,否则无法将数据插入到列中。例如,类型为 DECIMAL 的列不能插入到 INTEGER 列中,反之亦然。

示例代码迭代结果构建CREATE COLUMN TABLE DATA(K VARCHAR, V INT);INSERT INTO DATA VALUES('A', 123);INSERT INTO DATA VALUES('B', 45);INSERT INTO DATA VALUES('B', 67);INSERT INTO DATA VALUES('C', 890); CREATE PROCEDURE P(OUT OT DATA) ASBEGIN DECLARE I INT; LT0 = SELECT DISTINCT K FROM DATA; FOR I IN 1..RECORD_COUNT(:LT0) DO DECLARE K VARCHAR = :LT0.K[I]; LT1 = SELECT K, V + 1000 * :I AS V FROM DATA WHERE K = :K; :OT.INSERT(:LT1, 1); END FOR;END; CALL P(?)K V--------C 3.890B 2.045B 2.067A 1.123

更新表变量中的数据记录

您可以在特定位置修改数据记录。有两个等效的语法选项。

:.UPDATE((,…, )

[] = (,…, )

备注必须指定索引。 还可以为一组有限的列提供值。

:.(,…, ).UPDATE((,…, ), )

.(,…, )[] = (,…, )

备注省略的列的值保持不变。 示例代码CREATE TABLE TAB (V1 INT, V2 INT);INSERT INTO TAB VALUES(599, 7442);INSERT INTO TAB VALUES(5083, 4226);INSERT INTO TAB VALUES(7507, 3253);INSERT INTO TAB VALUES(8721, 1453);INSERT INTO TAB VALUES(8072, 2749);CREATE PROCEDURE MIRROR (IN IT TAB, OUT OT TAB) ASBEGIN DECLARE IDX INT; DECLARE MAXIDX INT = RECORD_COUNT(:IT); FOR IDX IN 1..MAXIDX DO OT[MAXIDX-IDX+1] = (:IT.V2[:IDX], :IT.V1[:IDX]); END FOR;END;CALL MIRROR(TAB, ?);V1 V2------------2.749 8.0721.453 8.7213.253 7.5074.226 5.0837.442 599 备注还可以在原始表大小之外的位置设置值。与 INSERT 一样,原始上一个记录和新插入记录之间的记录使用 NULL 值初始化。

从表变量中删除数据记录

您可以从表变量中删除数据记录。

删除单个记录

可以使用以下语法:

:.DELETE([  ])

如果未指定索引(位置),则删除所有记录。

如果索引超出表大小,则不执行任何操作。

示例代码CREATE TABLE HIER(PARENT VARCHAR(30), CHILD VARCHAR(30));INSERT INTO HIER VALUES ('root', 'A');INSERT INTO HIER VALUES ('root', 'B');INSERT INTO HIER VALUES ('A', 'C');INSERT INTO HIER VALUES ('C', 'D');INSERT INTO HIER VALUES ('A', 'E');INSERT INTO HIER VALUES ('E', 'F');INSERT INTO HIER VALUES ('E', 'G');CREATE PROCEDURE CALC_LEVEL (IN IT HIER, IN ROOT VARCHAR(30), OUT OT_LEVEL TABLE(NODE VARCHAR(30), L INT)) ASBEGIN DECLARE STACK TABLE(NODE VARCHAR(30), L INT); STACK[1] = (ROOT, 1); WHILE NOT IS_EMPTY(:STACK) DO DECLARE I INT; DECLARE NUM_CHILDREN INT; DECLARE CURR_NODE VARCHAR(30) = :STACK.NODE[1]; DECLARE CURR_LEVEL INT = :STACK.L[1]; CHILDREN = SELECT CHILD FROM :IT WHERE PARENT = CURR_NODE; :OT_LEVEL.INSERT((CURR_NODE, CURR_LEVEL)); NUM_CHILDREN = RECORD_COUNT(:CHILDREN); :STACK.DELETE(1); FOR I IN 1..NUM_CHILDREN DO :STACK.INSERT((:CHILDREN.CHILD[I], CURR_LEVEL + 1)); END FOR; END WHILE;END;CALL CALC_LEVEL(HIER, 'root', ?)NODE L-------root 1A 2B 2C 3E 3D 4F 4G 4

从表变量中删除记录块

要从表变量中删除记录块,可以使用以下语法:

:.DELETE(..)

如果起始索引大于表大小,则不执行任何操作。如果结束索引小于起始索引,则会发生错误。如果结束索引大于表大小,则会删除从起始索引到表末尾的所有记录。

示例代码CREATE TABLE PROD_PER_DATE (PROD_NAME VARCHAR(20), PROD_DATE DATE, NUM_DELTA INT);INSERT INTO PROD_PER_DATE VALUES ('PC', '20170105', 100);INSERT INTO PROD_PER_DATE VALUES ('PC', '20170106', 50);INSERT INTO PROD_PER_DATE VALUES ('PC', '20170117', 200);INSERT INTO PROD_PER_DATE VALUES ('Notebook', '20170320', 30);INSERT INTO PROD_PER_DATE VALUES ('Notebook', '20170322', 310);INSERT INTO PROD_PER_DATE VALUES ('Phone', '20170121', 20);INSERT INTO PROD_PER_DATE VALUES ('Phone', '20170205', 50);CREATE PROCEDURE TOTAL_NUM_EXCEEDS_CAPACITY ( IN IT PROD_PER_DATE, IN CAPACITY INT, OUT OT_RESULT TABLE(PROD_NAME VARCHAR(20), PROD_DATE DATE, NUM_TOTAL INT)) ASBEGIN DECLARE IDX INT = 0; DECLARE NUM_TOTAL INT = 0; DECLARE INTERVALS TABLE(FROM_IDX INT, TO_IDX INT); DECLARE FROM_IDX INT = 1; DECLARE TO_IDX INT = 0; OT_RESULT = SELECT PROD_NAME, PROD_DATE, NUM_DELTA AS NUM_TOTAL FROM :IT ORDER BY PROD_NAME, PROD_DATE; WHILE :OT_RESULT.PROD_NAME[IDX + 1] IS NOT NULL DO IDX = IDX+1; IF IDX > 1 THEN IF :OT_RESULT.PROD_NAME[IDX] <> :OT_RESULT.PROD_NAME[IDX - 1] THEN IF TO_IDX = 0 THEN TO_IDX = IDX - 1; END IF; IF FROM_IDX <= TO_IDX THEN :INTERVALS.INSERT((FROM_IDX, TO_IDX)); END IF; NUM_TOTAL = 0; FROM_IDX = IDX; TO_IDX = 0; END IF; END IF; NUM_TOTAL = NUM_TOTAL + :OT_RESULT.NUM_TOTAL[IDX]; OT_RESULT.NUM_TOTAL[IDX] = NUM_TOTAL; IF NUM_TOTAL > CAPACITY AND TO_IDX = 0 THEN TO_IDX = IDX - 1; END IF; END WHILE; IF TO_IDX = 0 THEN TO_IDX = IDX; END IF; :INTERVALS.INSERT((FROM_IDX, TO_IDX)); IDX = RECORD_COUNT(:INTERVALS); WHILE IDX > 0 DO :OT_RESULT.DELETE(:INTERVALS.FROM_IDX[IDX] .. :INTERVALS.TO_IDX[IDX]); IDX = IDX - 1; END WHILE;END;CALL TOTAL_NUM_EXCEEDS_CAPACITY(PROD_PER_DATE, 100, ?)PROD_NAME PROD_DATE NUM_TOTAL--------------------------------Notebook 22.03.2017 340PC 06.01.2017 150PC 17.01.2017 350 备注该算法仅适用于正增量值。

从表变量中删除所选记录

:.DELETE()

提供的数组表达式包含指向应从表变量中删除的记录的索引。如果数组包含无效索引(例如,零),则会发生错误。 示例代码CREATE TABLE PROD_PER_DATE (PROD_NAME VARCHAR(20), PROD_DATE DATE, NUM_DELTA INT);INSERT INTO DATE_VALUES VALUES ('PC', '20170105', 100);INSERT INTO DATE_VALUES VALUES ('PC', '20170106', -50);INSERT INTO DATE_VALUES VALUES ('PC', '20170117', 200);INSERT INTO DATE_VALUES VALUES ('Notebook', '20170320', 300);INSERT INTO DATE_VALUES VALUES ('Notebook', '20170322', -10);INSERT INTO DATE_VALUES VALUES ('Phone', '20170121', 20);INSERT INTO DATE_VALUES VALUES ('Phone', '20170205', 50); CREATE PROCEDURE TOTAL_NUM_EXCEEDS_CAPACITY ( IN IT PROD_PER_DATE, IN CAPACITY INT, OUT OT_RESULT TABLE(PROD_NAME VARCHAR(20), PROD_DATE DATE, NUM_TOTAL INT)) ASBEGIN DECLARE IDX INT = 0; DECLARE NUM_TOTAL INT = 0; DECLARE DEL_IDX INT ARRAY; DECLARE ARR_IDX INT = 0; OT_RESULT = SELECT PROD_NAME, PROD_DATE, NUM_DELTA AS NUM_TOTAL FROM :IT ORDER BY PROD_NAME, PROD_DATE; WHILE :OT_RESULT.PROD_NAME[IDX+1] IS NOT NULL DO IDX = IDX+1; IF IDX > 1 THEN IF :OT_RESULT.PROD_NAME[IDX] <> :OT_RESULT.PROD_NAME[IDX - 1] THEN NUM_TOTAL = 0; END IF; END IF; NUM_TOTAL = NUM_TOTAL + :OT_RESULT.NUM_TOTAL[IDX]; OT_RESULT.NUM_TOTAL[IDX] = NUM_TOTAL; IF NUM_TOTAL <= CAPACITY THEN ARR_IDX = ARR_IDX + 1; DEL_IDX[ARR_IDX] = IDX; END IF; END WHILE; :OT_RESULT.DELETE(:DEL_IDX);END;CALL TOTAL_NUM_EXCEEDS_CAPACITY(PROD_PER_DATE, 60, ?)PROD_NAME PROD_DATE NUM_TOTAL--------------------------------Notebook 20.03.2017 300Notebook 22.03.2017 290PC 05.01.2017 100PC 17.01.2017 250Phone 05.02.2017 70 备注此算法也适用于负增量值。