【问题标题】:batch update a column using sql使用 sql 批量更新列
【发布时间】:2017-09-19 07:13:16
【问题描述】:

我有一个包含大量行(几百万行)的数据库表 (db2)。我需要更改其中一列的数据类型。

在 DB2 LUW 中似乎没有办法直接更改列的数据类型(ALTER TABLE ALTER COLUMN SET DATA TYPE 不起作用)。所以我正在创建一个新列,将数据复制到它并删除旧列。

由于直接更新表不是一个好主意,因此我正在创建一个过程,该过程将一次更新和提交 10000 行。

鉴于此,我有以下问题:

  • 在此处执行更新的最佳方式是什么? - 据我所知,光标允许一次迭代超过 1 行。一次更新 10000 行,然后提交并重复,直到表被更新是正确的方法吗?
  • 有没有更好的方法来处理以更简单的方式更改列的数据类型的原始问题?

【问题讨论】:

  • 不需要存储过程,用pk条件代替一次更新10000行。
  • @jarlh 我不需要循环并在某个时候停止吗?如果没有程序,我该怎么做?
  • 什么 Db2 版本和平台?有哪些数据类型?您可以更改某些数据类型。并且有 ADMIN_MOVE_TABLE 来改变不兼容的类型。 ibm.com/support/knowledgecenter/SSEPGG_11.1.0/…
  • @data_henrik db2 10.5 LUW,从 varchar 更改为 clob。
  • 如果平均行长度也发生显着变化,可能会对页面大小产生后续影响,因此请仔细考虑是否也需要更改表空间。 CLOB 列对它们在 SQL 中的使用方式也有限制,并且由于处理大对象的方式,您还可能会在应用程序代码方面受到影响。在进行此更改之前,请务必谨慎进行影响评估。

标签: sql stored-procedures db2


【解决方案1】:

DB2 有一个称为 LOAD FROM CURSOR 的特性,它允许快速迁移数据。

以下是使用 LOAD FROM CURSOR 的示例:

-- this is the original table
CREATE TABLE TEST (
    ID INT NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    TEXT VARCHAR(50)
)@

CREATE TABLE TEST_NEW (
    ID INT NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    TEXT CLOB(5000000)
)@

DECLARE C1 CURSOR FOR SELECT ID, TEXT FROM TEST@

LOAD FROM C1 OF CURSOR INSERT INTO TEST_NEW (ID,TEXT)@ 

DROP TABLE TEST@
RENAME TABLE TEST_NEW TO TEST@

此外,还可以使用以下过程(每10000条记录后提交):

-- this is the original table
CREATE TABLE TEST (
    ID INT NOT NULL GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    TEXT VARCHAR(50)
)@

CREATE OR REPLACE PROCEDURE MIGRATE_TEST()
LANGUAGE SQL
BEGIN

    DECLARE EOF INT DEFAULT 0;

    DECLARE CUR_COUNT INT DEFAULT 0;
    DECLARE CUR_ID INT DEFAULT 0;

    DECLARE C CURSOR WITH HOLD FOR 
        SELECT ID FROM TEST WHERE TEXT_NEW IS NULL;

    DECLARE CONTINUE HANDLER FOR NOT FOUND 
        SET EOF = 1;

    OPEN C;

    FETCH_LOOP: LOOP
        FETCH FROM C INTO CUR_ID; 
        IF EOF <> 0 THEN
                LEAVE FETCH_LOOP;
        END IF;

        UPDATE TEST 
        SET TEXT_NEW = TEXT
        WHERE ID = CUR_ID ;

        SET CUR_COUNT = CUR_COUNT + 1;

        IF CUR_COUNT >= 10000 THEN
            CALL DBMS_OUTPUT.PUT_LINE('COMMITTING');
            COMMIT WORK;
            SET CUR_COUNT = 0;
        END IF;

    END LOOP FETCH_LOOP;

    COMMIT WORK;

    CLOSE C;
END@

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-28
    • 2016-12-27
    • 2012-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多