MySQL:从另一个表的随机行复制多个值

时间:2017-07-30 11:10:03

标签: mysql random sql-update

我已经为Microsoft SQL Server和PostGresql提出了类似的问题。在那里工作的解决方案不适用于MySQL。

我有两个表,stuffnonsense。我想将nonsense中随机行中的多个值复制到stuff中的每一行。当然,会有重复。

STUFF
+----+---------+-------------+--------+
| id | details | data        | more   |
+====+=========+=============+========+
| 1  | one     | (null)      | (null) |
| 2  | two     | (null)      | (null) |
| 3  | three   | (null)      | (null) |
| 4  | four    | (null)      | (null) |
| 5  | five    | (null)      | (null) |
| 6  | six     | (null)      | (null) |
+----+---------+-------------+--------+

NONSENSE
+----+---------+-------------+
| id | data    | more        |
+====+=========+=============+
| 1  | apple   | accordion   |
| 2  | banana  | banjo       |
| 3  | cherry  | cor anglais |
+----+---------+-------------+

我希望能够将这些内容复制到stuff表中:

UPDATE stuff SET data=?,more=?
FROM ?

我想得到以下内容:

+-----+----------+---------+-------------+
| id  | details  | data    | more        |
+=====+==========+=========+=============+
| 1   | one      | banana  | banjo       |
| 2   | two      | apple   | accordion   |
| 3   | three    | apple   | accordion   |
| 4   | four     | cherry  | cor anglais |
| 5   | five     | banana  | banjo       |
| 6   | six      | cherry  | cor anglais |
+-----+----------+---------+-------------+

这是一个适用于PostgreSQL的小提琴:http://sqlfiddle.com/#!17/313fb/8

如果它是单个值,我可以使用相关子查询,但它对于来自同一行的多个值不能正常工作。

较新的PostGresql可以从相关子查询中复制到多个列。 SQL Server OUTER APPLY子句,它允许FROM子句中的子查询相关。这两种方法都不适用于MySQL。

如何从另一个表中的随机行复制多个值?

2 个答案:

答案 0 :(得分:1)

不是很好看,但我认为这是一个解决方案。

从包含stuff.id和随机nonsense.id

的虚拟表开始
select id,(select id from nonsense order by rand() limit 1) as nid from stuff;

使用此虚拟表作为子查询加入stuff表:

stuff s
join
(select id,(select id from nonsense order by rand() limit 1) as nid from stuff) sq
on s.id=sq.id

使用相关子查询更新s.datas.more

set
    s.data=(select data from nonsense where id=sq.nid),
    s.more=(select more from nonsense where id=sq.nid);

这给出了:

update
    stuff s
    join
    (select id,(select id from nonsense order by rand() limit 1) as nid from stuff) sq
    on s.id=sq.id
set
    s.data=(select data from nonsense where id=sq.nid),
    s.more=(select more from nonsense where id=sq.nid);

应该有一个更顺畅的解决方案,但这是我能做的最好的。

答案 1 :(得分:0)

如果你只需要做一次并且不关心真正的随机,也许发明一个函数,它以某种方式将stuff.id映射到nonsense.id? 例如:

update stuff s, nonsense n
set s.data = n.data, s.more = n.more 
where n.id = s.id + 1 or n.id = ceil(s.id/2) -1;

对我来说看起来很像疯狂;)

http://sqlfiddle.com/#!9/dd0935/1

P.S。现在,认真......不能在sqlfiddle上试试,但是如果你有权访问mysql 8.0+版,你可以试试如下的smth:

with rn as (select n.data, n.more from stuff s, nonsense n order by rand())
update stuff, rn
set stuff.data = rn.data, stuff.more = rn.more;

更新:经过一些协作性脑力激荡后,发现了另外两个变种

update stuff s 
join (select id,(select id from nonsense order by rand() limit 1) as nid from stuff) sq on s.id=sq.id 
join nonsense n on n.id = sq.nid 
set s.data = n.data, s.more = n.more;


update stuff s 
join (select * from (select s.id as sid, n.data as sdata, n.more as smore from stuff s, nonsense n order by rand()) sn group by sn.sid) sgr on s.id = sgr.sid 
set s.data = sgr.sdata, s.more = sgr.smore;