我的表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
请帮帮我。非常感谢你!
答案 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
答案 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