我有这张桌子:
num | id | value1 | value2 | ..... | valueN
____|____|________|________|_______|_______
1 | 1 | val1 | val2 | ..... | valN
2 | 1 | blah | NULL | ..... | NULL
1 | 2 | val12 | val22 | ..... | valN2
2 | 2 | blah2 | NULL | ..... | NULL
num
和id
是主键。包含1 num
的每一行都是填充了所有列的行,id
的所有其他行(其中num
大于1)都有空列我想要填充使用num
= 1中具有相同id
的列中的相应值。
我可以编写一个在所有num
> 1行上运行的脚本,然后在每个空列上运行,并从num
= 1行开始运行但是有更多的SQLy方法吗?更一般的东西,没有迭代每一列?
答案 0 :(得分:1)
好吧,您可以尝试使用cross-table UPDATE JOIN
更新所有行UPDATE mytbl AS a
INNER JOIN (SELECT * FROM mytbl WHERE num = 1) AS b ON a.id = b.id
SET a.value1 = b.value1,
a.value2 = b.value2,
...
a.valueN = b.valueN
WHERE a.num > 1
答案 1 :(得分:1)
要更新值(并保留它们,如果已经存在),基本查询将如下所示:
update Table1 t
join (select * from Table1 where num = 1) ones
on t.id = ones.id and t.num != ones.num
set
t.value1 = IFNULL(t.value1, ones.value1),
t.value2 = IFNULL(t.value2, ones.value2),
t.valueN = IFNULL(t.valueN, ones.valueN);
由于无法执行update tablea from tableb set a.* = b.*
,您必须在查询中包含要更新的所有列,如果我理解您的问题,则这是您要避免的确切情况。
使用动态sql并查询数据库的信息模式,可以构建一个更新所有列的更新语句(手动排除的列除外)。
这个方法有点hackish但是应该可行,但它可能效果不好而且可能不安全。如果将名为Table1
的测试表设置为您的示例,则可以运行以下代码来更新除id
和num
以外的所有列:
-- base update statement
SET @sql:= 'update Table1 t
join (select * from Table1 where num = 1) ones
on t.id = ones.id and t.num != ones.num
set ';
-- concatenate the base update with the column specific part
SELECT @stmnt := concat(@sql, group_concat(
't.',
COLUMN_NAME,
' = IFNULL(t.',
COLUMN_NAME,'
, ones.',
COLUMN_NAME,
')'))
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'Table1'
-- exclude these columns from the update
AND column_name != 'id'
AND column_name != 'num';
-- build a statement and execute it
PREPARE dynamic_statement FROM @stmnt;
EXECUTE dynamic_statement;
DEALLOCATE PREPARE dynamic_statement;