使用我的sql随机选择独占记录

时间:2016-08-23 01:13:07

标签: mysql select

我的表A如下

id (integer)
follow_up (integer, days under observation)
matched_id (integer)


id   ; follow_up  ; matched_id
1    ; 10              ; 19
1    ; 10              ; 20
1    ; 10              ; 21
2    ; 5               ; 22
2    ; 5               ; 23
2    ; 5               ; 24
2    ; 5               ; 19
2    ; 5               ; 20
3    ; 6               ; 25
3    ; 6               ; 26
3    ; 6               ; 27
4    ; 7               ; 19
4    ; 7               ; 28
4    ; 7               ; 29

我想限制为每个id 2条记录,并且记录应该随机选取并且对每个id都是独占的。例如 matched_id:" 19"和" 20"被赋予id:1,然后" 19"和" 20"不应该给id:2 matched_id:" 19"给了id:1,然后" 19"不应该给id:4 等表格的其余部分。

需要输出

id   ; follow_up  ; matched_id
1    ; 10              ; 19
1    ; 10              ; 20
2    ; 5               ; 22
2    ; 5               ; 23
3    ; 6               ; 25
3    ; 6               ; 26
4    ; 7               ; 28
4    ; 7               ; 29

请帮帮我。非常感谢你!

3 个答案:

答案 0 :(得分:0)

这是一个非常好且非常具有挑战性的SQL问题。

您有一系列非常具有挑战性的要求:   1.在结果集中,match_id不应出现多次   2.没有ID超过两场比赛   3.匹配是随机的

我们将坚持使用纯SQL解决方案,假设您无法返回更大的结果集,并使用实现语言中的业务逻辑进行一些过滤。

首先,让我们解决随机分配问题。随机订购组内的项目是一个有趣的问题。我决定通过对行中数据(id,follow_up,matched_id)的SHA1哈希进行排序来解决它,这将给出可重复的结果和随机性。 (如果有一个列包含创建或修改的日期/时间,那将是最好的。)

SELECT * FROM
(
  SELECT
    a.id,
    a.follow_up,
    a.matched_id,
    a.rank_hash,
    count(*) rank
  FROM
  (SELECT *, SHA1(CONCAT(id, follow_up, matched_id)) rank_hash FROM TableA) a
  JOIN 
  (SELECT *, SHA1(CONCAT(id, follow_up, matched_id)) rank_hash FROM TableA) b
  ON a.rank_hash >= b.rank_hash
  AND a.id = b.id
  GROUP BY a.id, a.matched_id
  ORDER BY a.id, rank
) groups
WHERE rank <= 2
GROUP BY matched_id

如果每个id有足够的matched_id值,这可能就足够了。但如果有一个隐藏的第四个要求怎么办:   4.如果可能,ID应该收到匹配。

换句话说,如果作为随机混洗的结果,match_id被分配给具有多个其他匹配的id,但是在结果集中进一步向下,则匹配ID?可以使用每个ID与matched_id匹配的最佳解决方案,但它从未发生过,因为所有的matched_id都在此过程的早期用完了?

例如:

CREATE TABLE TableA
    (`id` int, `follow_up` int, `matched_id` varchar(1))
;

INSERT INTO TableA
    (`id`, `follow_up`, `matched_id`)
VALUES
    (1, 10, 'A'),
    (1, 10, 'B'),
    (1, 10, 'C'),
    (2, 5, 'D'),
    (2, 5, 'E'),
    (2, 5, 'F'),
    (3, 5, 'C')
;

在上面的设置中,如果ID和它们的匹配是随机分配的,如果ID 1被分配了matched_id C,那么ID 3将根本不会得到matched_id。

如果我们首先找出收到的ID匹配的数量,并按顺序排序,该怎么办?

SELECT 
  a.*,
  frequency
FROM TableA a
JOIN 
( SELECT
    matched_id,
    count(*) frequency
  FROM
    TableA
  GROUP BY matched_id
) b
ON a.matched_id = b.matched_id
GROUP BY a.matched_id
ORDER BY b.frequency

这是中间人编程语言可能派上用场来帮助限制结果集的地方。

但请注意,我们也失去了随机性的要求!正如您所看到的,纯SQL解决方案可能会非常难看。确实可以结合上述技术。

希望这会激发你的想象力。

答案 1 :(得分:0)

RAND()MySQL user defined variables一起,您可以实现此目标:

SELECT 
t.id,
t.follow_up,
t.matched_id
FROM 
(
    SELECT 
    randomTable.*,
    IF(@sameID = id, @rn := @rn + 1,
        IF(@sameID := id, @rn := 1, @rn := 1)
    ) AS rowNumber
    FROM 
    (
        SELECT 
        *
        FROM tableA
        ORDER BY id, RAND()
    ) AS randomTable
    CROSS JOIN (SELECT @sameID := 0, @rn := 0) var
) AS t
WHERE t.rowNumber <= 2
ORDER BY t.id

See Demo

答案 2 :(得分:0)

这是针对特定问题的解决方案。它不会扩展!

SELECT *
  FROM
     ( SELECT a.matched_id m1
            , b.matched_id m2
            , c.matched_id m3
            , d.matched_id m4
         FROM my_table a
         JOIN my_table b
           ON b.matched_id NOT IN(a.matched_id)
         JOIN my_table c
           ON c.matched_id NOT IN(a.matched_id,b.matched_id)
         JOIN my_table d
           ON d.matched_id NOT IN(a.matched_id,b.matched_id,c.matched_id)
        WHERE a.id = 1
          AND b.id = 2
          AND c.id = 3
          AND d.id = 4
     ) x
  JOIN
     ( SELECT a.matched_id n1
            , b.matched_id n2
            , c.matched_id n3
            , d.matched_id n4
         FROM my_table a
         JOIN my_table b
           ON b.matched_id NOT IN(a.matched_id)
         JOIN my_table c
           ON c.matched_id NOT IN(a.matched_id,b.matched_id)
         JOIN my_table d
           ON d.matched_id NOT IN(a.matched_id,b.matched_id,c.matched_id)
        WHERE a.id = 1
          AND b.id = 2
          AND c.id = 3
          AND d.id = 4
     ) y
    ON y.n1 NOT IN(x.m1,x.m2,x.m3,x.m4)
   AND y.n2 NOT IN(x.m1,x.m2,x.m3,x.m4)
   AND y.n3 NOT IN(x.m1,x.m2,x.m3,x.m4)
   AND y.n4 NOT IN(x.m1,x.m2,x.m3,x.m4)
 ORDER 
    BY RAND() LIMIT 1;

+----+----+----+----+----+----+----+----+
| m1 | m2 | m3 | m4 | n1 | n2 | n3 | n4 |
+----+----+----+----+----+----+----+----+
| 20 | 24 | 27 | 29 | 21 | 23 | 26 | 28 |
+----+----+----+----+----+----+----+----+

因此,在这个例子中,对是:

id1: 20,21
id2: 24,23
id3: 27,26
id4: 29,28