我开发了一个 SQL 存储过程,旨在自动在一群人中抽奖神秘圣诞老人。该程序应该为每个人随机分配其他人礼物,而不是任何人自己赠送礼物。然而,我遇到了一个问题,个人最终可能被分配给自己送礼物,这在秘密圣诞老人设置中是不希望的。
这是我正在使用的 SQL 代码:
CREATE DATABASE IF NOT EXISTS AMIGOINVISIBLE;
USE AMIGOINVISIBLE;
CREATE TABLE IF NOT EXISTS CaseA(
id INT PRIMARY KEY AUTO_INCREMENT,
people VARCHAR(50),
peopleToGift VARCHAR(50) );
INSERT INTO CaseA (people, peopleToGift)
VALUES ('a.tomas', NULL), ('g.rubio', NULL), ('a.pulido', NULL), ('m.fabrega.1', NULL), ('d.lazaro', NULL), ('c.albinya', NULL), ('b.gomez', NULL),`
`('j.espinoza', NULL), ('j.aguilera', NULL), ('j.da.silva.1', NULL), ('a.chamorro', NULL);
DELIMITER //
CREATE OR REPLACE PROCEDURE randomizePeople()
BEGIN
DECLARE times INT;
DECLARE Counter INT;
DECLARE random1 INT;
DECLARE random2 INT;
DECLARE aux INT;
DECLARE position INT;
DECLARE peopleToGift VARCHAR(50);
SELECT COUNT(*) INTO times FROM CaseA;
DROP TABLE IF EXISTS order;
CREATE TEMPORARY TABLE IF NOT EXISTS order (
id INT PRIMARY KEY AUTO_INCREMENT,
Number INT
);
SET Counter = 1;
WHILE Counter <= times DO
INSERT INTO order (Number) VALUES (Counter);
SET Counter = Counter + 1;
END WHILE;
SET Counter = 1;
WHILE Counter <= times DO
SET random1 = FLOOR(RAND() * times) + 1;
SET random2 = FLOOR(RAND() * times) + 1;
SELECT Number INTO aux FROM order WHERE id = random1;
UPDATE order SET Number = (SELECT Number FROM order WHERE id = random2) WHERE id = random1;
UPDATE order SET Number = aux WHERE id = random2;
SET Counter = Counter + 1;
END WHILE;
SET Counter = 1;
WHILE Counter <= times DO
SELECT Number INTO position FROM order WHERE id = Counter;
SELECT people INTO peopleToGift FROM CaseA WHERE id = position;
SELECT position, peopleToGift;
UPDATE CaseA SET peopleToGift = peopleToGift WHERE id = Counter;
SET Counter = Counter + 1;
END WHILE;
END
// DELIMITER;
DELIMITER ;
您可以通过首先为每个人随机分配一个行号来做到这一点:
SELECT id, people, ROW_NUMBER() OVER(ORDER BY RAND()) AS RowNumber, COUNT(*) OVER() AS TotalCount
FROM CaseA
然后您可以将每个人与下一个人配对,例如RowNumber 1 和 RowNumber2 等,这确保没有人可以与自己配对。唯一需要注意的是,您需要将最后一行与第一行配对,因此您需要对连接使用模数检查来执行此操作。
作为选择,它看起来像这样:
WITH RandomOrder AS
( SELECT id,
people,
ROW_NUMBER() OVER(ORDER BY RAND()) AS RowNumber,
COUNT(*) OVER() AS TotalCount
FROM CaseA
)
SELECT r1.id, r1.people, r1.RowNumber, r2.people AS peopleToGift
FROM RandomOrder AS r1
INNER JOIN RandomOrder AS r2
ON r2.RowNumber = (r1.RowNumber % r1.TotalCount) + 1
ORDER BY r1.id;
或者要更新基表本身,您可以将其转换为更新,如下所示:
WITH RandomOrder AS
( SELECT id,
people,
ROW_NUMBER() OVER(ORDER BY RAND()) AS RowNumber,
COUNT(*) OVER() AS TotalCount
FROM CaseA
)
UPDATE CaseA AS c
INNER JOIN RandomOrder AS r1
ON r1.id = c.id
INNER JOIN RandomOrder AS r2
ON r2.RowNumber = (r1.RowNumber % r1.TotalCount) + 1
SET c.PeopleToGift = r2.people;