【问题标题】:Update columns in DB2 using randomly chosen static values provided at runtime使用运行时提供的随机选择的静态值更新 DB2 中的列
【发布时间】:2018-05-02 13:53:41
【问题描述】:

我想使用从一组可能值中随机选择的值来更新行。

理想情况下,我可以在运行时使用 Java 应用程序中的 JdbcTemplate 提供这些值。

示例: 在表中,“名称”列可以包含任何名称。目标是遍历表并将所有名称更改为等于“Bob”或“Alice”。

我知道这可以通过创建一个 sql 函数来完成。我测试了它,它很好,但我想知道是否可以只使用简单的查询?

这行不通,似乎该值只计算一次,并应用于所有行:

UPDATE test.table
SET first_name = 
    (SELECT a.name 
     FROM 
         (SELECT a.name, RAND() idx 
          FROM (VALUES('Alice'), ('Bob')) AS a(name) ORDER BY idx FETCH FIRST 1 ROW ONLY) as a)
;

我尝试使用MERGE INTO,但它甚至无法运行(在SET 查询中找不到possible_names)。我还没有弄清楚为什么:

MERGE INTO test.table
    USING
        (SELECT
            names.fname 
        FROM 
            (VALUES('Alice'), ('Bob'), ('Rob')) AS names(fname)) AS possible_names
    ON ( test.table.first_name IS NOT NULL )
    WHEN MATCHED THEN 
        UPDATE SET
        -- select random name
        first_name = (SELECT fname FROM possible_names ORDER BY idx FETCH FIRST 1 ROW ONLY)
; 

编辑:如果可能,我只想关注正在更新的字段,而不是依赖于知道主键等。

【问题讨论】:

    标签: sql jdbc db2 jdbctemplate


    【解决方案1】:

    Db2 似乎正在优化返回您所谓的随机名称的子选择,只实现一次,因此目标表中的所有行都接收相同的值。

    要强制为每一行执行子选择,您需要以某种方式将其与正在更新的表相关联,例如:

    UPDATE test.table
    SET first_name = 
        (SELECT a.name 
         FROM (VALUES('Alice'), ('Bob')) AS a(name) 
         ORDER BY RAND(ASCII(SUBSTR(first_name, 1, 1))) 
         FETCH FIRST 1 ROW ONLY)
    

    甚至可能是

    UPDATE test.table
    SET first_name = 
        (SELECT a.name 
         FROM (VALUES('Alice'), ('Bob')) AS a(name) 
         ORDER BY first_name, RAND() 
         FETCH FIRST 1 ROW ONLY)
    

    既然 subselect 的结果似乎依赖于目标表中对应行的值,那么只能对每一行执行它。

    【讨论】:

    • 是的,听起来它应该可以工作,但经过一些测试,似乎子选择仍然被优化掉了。
    • 我对其进行了测试,它的工作原理与 Db2 for LUW 10.5 上的描述一样
    【解决方案2】:

    如果您的表有主键,这将有效。我假设 PK 是列id

    UPDATE test.table t
    SET first_name = 
    ( SELECT name from
        ( SELECT *, ROW_NUMBER() OVER(PARTITION BY id ORDER BY R) AS RN FROM 
            ( SELECT *, RAND() R
              FROM test.table, TABLE(VALUES('Alice'), ('Bob')) AS d(name)  
             )
         )
     AS u
    WHERE t.id = u.id and rn = 1
    )
    ;
    

    可能有更好/更有效的解决方案,但我会把它留给其他人。

    仅供参考,我使用以下 DDL 和数据来测试上述内容。

    create table test.table(id int not null primary key, first_name varchar(32));
    insert into test.table values (1,'Flo'),(2,'Fred'),(3,'Sue'),(4,'John'),(5,'Jim');
    

    【讨论】:

    • 我不得不稍微修改一下,但是,如果主键已知,它可以工作。对于我的问题,我只想关注正在更新的字段。
    • 另一个答案中的代码应该可以工作。如果更改查询的语义,Db2 不会优化掉相关性。您需要确保对相关子选择中的更新表有非冗余引用。这是一个稍微小一点的版本UPDATE test.table t SET first_name = (SELECT * FROM (VALUES('Alice'), ('Bob')) ORDER BY RAND(), t.first_name LIMIT 1)
    猜你喜欢
    • 2021-06-23
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 2012-10-09
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多