mysql随机唯一前数据,来自一列表(无主键)

bakd9h0s  于 2021-07-24  发布在  Java
关注(0)|答案(3)|浏览(309)

我需要从表中提取数据(所有数据的100%),并将其拆分为3列。
示例:我们有数据:

numbers
80174
91467
1105
12040
62224
46508
33149
61384
10811
84923

我们需要采取:

| Random 60% of all | Random  40% of all
      | unique and not    | unique and not 
  All | contained in 40%  | contained in 60% 
      | of the column     | of the column
----------------------------------------------
80174 |      84923        |      33149
91467 |      91467        |      61384
1105  |       1105        |      10811
12040 |      62224        |      80174
62224 |      12040        |     
46508 |      46508        |     
33149 |                   |
61384 |                   |
10811 |                   |
84923 |                   |
hgtggwj0

hgtggwj01#

它使用order by rand()函数将行随机分配,并使用mysql 8窗口函数row\u number将第一个数字拆分为60/40,然后再将其合并。
您可以在mysql 5.x中重建row\u number函数,但它没有那么漂亮
编辑torpas建议后,计算必要的行数。编辑2:在福帕斯的另一个评论之后,我用兰德取代了ceil
我认为必须有一个精确的解决方案,其中更多的是使用模

CREATE TABLE Table1
    (`numbers` int)
;

INSERT INTO Table1
    (`numbers`)
VALUES
    (80174),
    (91467),
    (1105),
    (12040),
    (62224),
    (46508),
    (33149),
    (61384),
    (10811),
    (84923),
    (80179),
    (91469),
    (1109),
    (12049),
    (62229)    
;
WITH rand_num as (SELECT `numbers`, ROW_NUMBER() OVER (ORDER BY RAND()) as rn FROM Table1 ),
limitscal as (SELECT ROUND((COUNT(*)  * 6 / 10),0)  si_x  FROM Table1),
countcal as (SELECT COUNT(*)  cnt  FROM Table1),
60_num as (SELECT `numbers`, ROW_NUMBER() OVER (ORDER BY RAND()) as rn2 
            FROM  rand_num CROSS JOIN limitscal CROSS JOIN countcal
            WHERE rn MOD countcal.cnt < limitscal.si_x)
,40_num as (SELECT `numbers`, ROW_NUMBER() OVER (ORDER BY RAND()) as rn2 
            FROM  rand_num CROSS JOIN limitscal  CROSS JOIN countcal 
            WHERE rn MOD countcal.cnt >= limitscal.si_x )
SELECT 6_n.`numbers`,4_n.`numbers` FROM 60_num 6_n LEFT JOIN 40_num 4_n ON 6_n.rn2 = 4_n.rn2
numbers | numbers
------: | ------:
  10811 |   61384
  80174 |   12049
  12040 |   46508
  91467 |   84923
  80179 |    1109
  91469 |   62224
  33149 |    null
   1105 |    null
  62229 |    null

db<>在这里摆弄

6ie5vjzr

6ie5vjzr2#

您可以根据指定分组 rand() :

select t.*, (case then rand() < 0.6 then 1 else 2 end) as grouping
from t;

请注意,这大约是60%/40%。如果要精确拆分,可以使用窗口函数:

select t.*,
       (case when seqnum <= 0.6 * cnt then 1 else 2 end) as grouping
from (select t.*, count(*) over () as cnt, row_number() over (order by rand()) as seqnum
      from t
     ) t
vmpqdwk3

vmpqdwk33#

你想随机给你的行编号。你想做两次。一次用于随机拆分为60%和40%,一次用于所有列的随机排序。
从mysql 8开始,您可以使用window函数 ROW_NUMBER 为了这个。两倍于 row_number() over (order by rand()) 但是,会导致相同的随机顺序出现两次,因为mysql看到您使用相同的表达式进行排序。所以,稍微修改一下表达式,例如,添加两个不同的常数。
其余的两个外部连接到100%行,一个连接60%,一个连接其余的40%。

with prepared as
(
  select
    number,
    row_number() over (order by rand() + 0) as rn1,
    row_number() over (order by rand() + 1) as rn2,
    count(*) over () as cnt
  from numbers
)
, p100 as (select rn1 as rn, number from prepared)
, p60 as (select rn2 as rn, number from prepared where rn2 / cnt <= 0.6)
, p40 as (select cnt - rn2 + 1 as rn, number from prepared where rn2 / cnt > 0.6)
select
  p100.number as number1,
  p60.number as number2,
  p40.number as number3
from p100
left join p60 on p60.rn = p100.rn
left join p40 on p40.rn = p100.rn
order by p100.rn;

演示:https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=b14419fd15f8a7987c10f2ef25ced826

相关问题