使用运行时提供的随机选择的静态值更新DB2中的列

时间:2018-05-02 13:53:42

标签: sql jdbc db2 jdbctemplate

我想更新具有从一组可能值中随机选择的值的行。

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

实施例: 在表中,“name”列可以包含任何名称。目标是遍历表并将所有名称更改为等于“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)
; 

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

2 个答案:

答案 0 :(得分:2)

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的结果似乎依赖于目标表中相应行的值,那么除了为每一行执行它之外别无选择。

答案 1 :(得分:1)

如果您的表有主键,这将有效。我假设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');