我想更新具有从一组可能值中随机选择的值的行。
理想情况下,我可以使用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)
;
编辑:如果可能的话,我想只关注正在更新的字段,而不是依赖于知道主键等。
答案 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');