如果它们是奇数,如何删除重复的行,否则保留一个
How to delete duplicate rows if they are odd else keep one
这是一款卡牌游戏。
我的 table 是
Number
Symbol
Player
1
C
F
1
S
F
1
D
F
1
H
F
2
S
F
2
C
F
2
D
F
3
H
F
2
H
S
3
S
S
我正在尝试移除玩家 F 的所有 1 张牌,因为他有偶数张牌并且他已经收集了所有牌。
我只想从播放器 F 中删除 2 张牌中的 2 行,因为他有奇数个,最后 2 个在 S 播放器上
我正在尝试为此创建一个程序,我只设法让播放器保持一排
PROCEDURE `deleteDupl`()
BEGIN
DELETE c1 FROM cards c1, cards c2 WHERE c1.Symbol > c2.Symbol AND c1.Number = c2.Number AND c1.Player = c2.Player;
END
--编辑
游戏的重点是从你的对手那里挑选卡片,一旦你有 2 张相同的卡片(卡片的数量而不是符号),你将它们丢弃(无论什么符号只是随机丢弃 2 个相同的数字)
但在游戏开始时,您可能会得到超过 2 张相同的牌,例如 F 玩家拥有所有 A,因此他必须将它们全部放下
或者像 F 玩家有 2 张牌的三倍他必须丢弃两张牌(无论是什么符号),直到他从对手那里选择号码为 2 的牌
你还没有说你是哪个 MySQL 版本 运行。此存储过程示例适用于 MySQL 5.6。它运行一个简单的 GROUP BY 查询来获取所有 Number, Player groups with more than 1 card。然后它遍历游标并为返回的每一行运行删除。
CREATE PROCEDURE `sp_DeletePairs`()
BEGIN
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE _number TINYINT UNSIGNED;
DECLARE _player CHAR(20);
DECLARE _count TINYINT UNSIGNED;
DECLARE `cur` CURSOR FOR
SELECT `Number`, `Player`, COUNT(*) AS `num`
FROM `cards`
GROUP BY `Number`, `Player`
HAVING `num` > 1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO _number, _player, _count;
IF done THEN
LEAVE read_loop;
END IF;
CASE
WHEN _count IN (2, 3) THEN
DELETE FROM `cards` WHERE `Number` = _number AND `Player` = _player LIMIT 2;
WHEN _count = 4 THEN
DELETE FROM `cards` WHERE `Number` = _number AND `Player` = _player LIMIT 4;
END CASE;
END LOOP;
CLOSE cur;
END
显然,如果您愿意,可以将以下 DELETE 查询示例包装在存储过程中。
如果您使用的是 MySQL 8.0 或更高版本,您可以使用 window functions -
WITH `stats` AS (
SELECT `Number`, `Symbol`, `Player`,
ROW_NUMBER() OVER (PARTITION BY `Number`, `Player` ORDER BY `Player`, `Number`, `Symbol`) AS `seq`,
COUNT(*) OVER (PARTITION BY `Number`, `Player`) AS `count_numbers`
FROM cards
)
DELETE `c`
FROM `cards` `c`
INNER JOIN `stats` `s`
ON `c`.`Number` = `s`.`Number`
AND `c`.`Symbol` = `s`.`Symbol`
AND `c`.`Player` = `s`.`Player`
WHERE `s`.`count_numbers` = 4
OR (`s`.`count_numbers` IN (2, 3) AND `s`.`seq` IN (1, 2));
在 CTE, the ROW_NUMBER() 中为我们提供了 Number
、Player
分区中的累积计数。 COUNT(*)
为我们提供了 Number
、Player
分区内的总数。然后,我们可以在所有三个原始列上加入 stats
(CTE)和 cards
。最后,我们使用 WHERE 子句来决定删除哪些卡片。
在 MySQL < 8.0 中可以采用类似的方法,使用序列变量和连接到另一个派生的 table 以获得每组的计数 -
DELETE `c`
FROM `cards` `c`
INNER JOIN (
SELECT
`c`.`Number`,
`c`.`Symbol`,
`c`.`Player`,
IF(@prev_number = `c`.`Number` AND @prev_player = `c`.`Player`, @row := @row + 1, @row := 1) AS `seq`,
`counts`.`count_numbers`,
@prev_number := `c`.`Number`,
@prev_player := `c`.`Player`
FROM `cards` `c`
JOIN (SELECT @row := 0, @prev_number := 0, @prev_player:=0) t
INNER JOIN ( SELECT `Player`, `Number`, COUNT(*) AS `count_numbers` FROM `cards` GROUP BY `Player`, `Number`) AS `counts`
ON `c`.`Player` = `counts`.`Player`
AND `c`.`Number` = `counts`.`Number`
ORDER BY `c`.`Player`, `c`.`Number`
) `s`
ON `c`.`Number` = `s`.`Number`
AND `c`.`Symbol` = `s`.`Symbol`
AND `c`.`Player` = `s`.`Player`
WHERE `s`.`count_numbers` = 4
OR (`s`.`count_numbers` IN (2, 3) AND `s`.`seq` IN (1, 2));
我绝对不建议使用最后一个示例,至少不建议在生产环境中使用。我只是包括在内,因为它可能对某些人来说很有趣。
这是一款卡牌游戏。 我的 table 是
Number | Symbol | Player |
---|---|---|
1 | C | F |
1 | S | F |
1 | D | F |
1 | H | F |
2 | S | F |
2 | C | F |
2 | D | F |
3 | H | F |
2 | H | S |
3 | S | S |
我正在尝试移除玩家 F 的所有 1 张牌,因为他有偶数张牌并且他已经收集了所有牌。 我只想从播放器 F 中删除 2 张牌中的 2 行,因为他有奇数个,最后 2 个在 S 播放器上
我正在尝试为此创建一个程序,我只设法让播放器保持一排
PROCEDURE `deleteDupl`()
BEGIN
DELETE c1 FROM cards c1, cards c2 WHERE c1.Symbol > c2.Symbol AND c1.Number = c2.Number AND c1.Player = c2.Player;
END
--编辑 游戏的重点是从你的对手那里挑选卡片,一旦你有 2 张相同的卡片(卡片的数量而不是符号),你将它们丢弃(无论什么符号只是随机丢弃 2 个相同的数字)
但在游戏开始时,您可能会得到超过 2 张相同的牌,例如 F 玩家拥有所有 A,因此他必须将它们全部放下
或者像 F 玩家有 2 张牌的三倍他必须丢弃两张牌(无论是什么符号),直到他从对手那里选择号码为 2 的牌
你还没有说你是哪个 MySQL 版本 运行。此存储过程示例适用于 MySQL 5.6。它运行一个简单的 GROUP BY 查询来获取所有 Number, Player groups with more than 1 card。然后它遍历游标并为返回的每一行运行删除。
CREATE PROCEDURE `sp_DeletePairs`()
BEGIN
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE _number TINYINT UNSIGNED;
DECLARE _player CHAR(20);
DECLARE _count TINYINT UNSIGNED;
DECLARE `cur` CURSOR FOR
SELECT `Number`, `Player`, COUNT(*) AS `num`
FROM `cards`
GROUP BY `Number`, `Player`
HAVING `num` > 1;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN cur;
read_loop: LOOP
FETCH cur INTO _number, _player, _count;
IF done THEN
LEAVE read_loop;
END IF;
CASE
WHEN _count IN (2, 3) THEN
DELETE FROM `cards` WHERE `Number` = _number AND `Player` = _player LIMIT 2;
WHEN _count = 4 THEN
DELETE FROM `cards` WHERE `Number` = _number AND `Player` = _player LIMIT 4;
END CASE;
END LOOP;
CLOSE cur;
END
显然,如果您愿意,可以将以下 DELETE 查询示例包装在存储过程中。
如果您使用的是 MySQL 8.0 或更高版本,您可以使用 window functions -
WITH `stats` AS (
SELECT `Number`, `Symbol`, `Player`,
ROW_NUMBER() OVER (PARTITION BY `Number`, `Player` ORDER BY `Player`, `Number`, `Symbol`) AS `seq`,
COUNT(*) OVER (PARTITION BY `Number`, `Player`) AS `count_numbers`
FROM cards
)
DELETE `c`
FROM `cards` `c`
INNER JOIN `stats` `s`
ON `c`.`Number` = `s`.`Number`
AND `c`.`Symbol` = `s`.`Symbol`
AND `c`.`Player` = `s`.`Player`
WHERE `s`.`count_numbers` = 4
OR (`s`.`count_numbers` IN (2, 3) AND `s`.`seq` IN (1, 2));
在 CTE, the ROW_NUMBER() 中为我们提供了 Number
、Player
分区中的累积计数。 COUNT(*)
为我们提供了 Number
、Player
分区内的总数。然后,我们可以在所有三个原始列上加入 stats
(CTE)和 cards
。最后,我们使用 WHERE 子句来决定删除哪些卡片。
在 MySQL < 8.0 中可以采用类似的方法,使用序列变量和连接到另一个派生的 table 以获得每组的计数 -
DELETE `c`
FROM `cards` `c`
INNER JOIN (
SELECT
`c`.`Number`,
`c`.`Symbol`,
`c`.`Player`,
IF(@prev_number = `c`.`Number` AND @prev_player = `c`.`Player`, @row := @row + 1, @row := 1) AS `seq`,
`counts`.`count_numbers`,
@prev_number := `c`.`Number`,
@prev_player := `c`.`Player`
FROM `cards` `c`
JOIN (SELECT @row := 0, @prev_number := 0, @prev_player:=0) t
INNER JOIN ( SELECT `Player`, `Number`, COUNT(*) AS `count_numbers` FROM `cards` GROUP BY `Player`, `Number`) AS `counts`
ON `c`.`Player` = `counts`.`Player`
AND `c`.`Number` = `counts`.`Number`
ORDER BY `c`.`Player`, `c`.`Number`
) `s`
ON `c`.`Number` = `s`.`Number`
AND `c`.`Symbol` = `s`.`Symbol`
AND `c`.`Player` = `s`.`Player`
WHERE `s`.`count_numbers` = 4
OR (`s`.`count_numbers` IN (2, 3) AND `s`.`seq` IN (1, 2));
我绝对不建议使用最后一个示例,至少不建议在生产环境中使用。我只是包括在内,因为它可能对某些人来说很有趣。