Force Union 以避免得到重复的结果,然后将其删除?
Force Union to avoid getting a duplicate result which is then removed?
我有一个查询如下:
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Common'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 7)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity != 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
第三个查询的逻辑是它有可能是普通的或高于稀有的稀有度。目前这是一个随机机会,所以顺序如下:
- 7 个公地
- 1 稀有
- 1 个普通或高于稀有的稀有度
因为我使用的是UNION
,所以重复项被删除了。我知道我可以使用 UNION ALL
来保留重复项,但问题是我需要在不删除任何内容的情况下没有重复项。
我绝对需要 9 个结果,但通过上面的查询,我偶尔可以获得 8 个结果,因为最后一个查询可以获得与前 7 个相同的结果之一。
是否有一种纯粹的 SQL 方法来解决这个问题,还是我必须求助于 PHP?
从 PHP 的角度来看,我可以执行前两个查询,将第一个查询的所有结果推送到一个数组中,然后执行第三个查询并告诉它也避免存储在该数组中的任何结果.
这是迄今为止我能想到的唯一解决方法。
MySQL 版本:5.6.45-cll-lve
如果你用的是MySQL8,你可以用一个common table expression,比如:
WITH cte AS
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Common'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 7)
SELECT * FROM cte
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity != 'Rare'
AND cr.set_code like '%lob%'
AND cr.id NOT IN (SELECT c.id FROM cte) -- <---- check this
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
我认为以下内容可行(它应该是 sql 等同于我在上面评论中发布的想法):
SELECT * FROM(
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity != 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Common'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 8) -- Set this limit to 8
) AS t LIMIT 9 -- then take first 9
编辑:更新了它,因为我以前的版本仍然可能失败并且 return 只有 8 个结果
然后,如果您需要按照原始查询的特定顺序反转 PHP 中的数组
我有一个查询如下:
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Common'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 7)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity != 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
第三个查询的逻辑是它有可能是普通的或高于稀有的稀有度。目前这是一个随机机会,所以顺序如下:
- 7 个公地
- 1 稀有
- 1 个普通或高于稀有的稀有度
因为我使用的是UNION
,所以重复项被删除了。我知道我可以使用 UNION ALL
来保留重复项,但问题是我需要在不删除任何内容的情况下没有重复项。
我绝对需要 9 个结果,但通过上面的查询,我偶尔可以获得 8 个结果,因为最后一个查询可以获得与前 7 个相同的结果之一。
是否有一种纯粹的 SQL 方法来解决这个问题,还是我必须求助于 PHP?
从 PHP 的角度来看,我可以执行前两个查询,将第一个查询的所有结果推送到一个数组中,然后执行第三个查询并告诉它也避免存储在该数组中的任何结果.
这是迄今为止我能想到的唯一解决方法。
MySQL 版本:5.6.45-cll-lve
如果你用的是MySQL8,你可以用一个common table expression,比如:
WITH cte AS
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Common'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 7)
SELECT * FROM cte
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity != 'Rare'
AND cr.set_code like '%lob%'
AND cr.id NOT IN (SELECT c.id FROM cte) -- <---- check this
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
我认为以下内容可行(它应该是 sql 等同于我在上面评论中发布的想法):
SELECT * FROM(
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity != 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Rare'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 1)
UNION
(SELECT cr.id, cr.price, cd.times, cd.name, cr.rarity
FROM rarity_db cr
JOIN card_db cd
ON cr.id = cd.id
WHERE cr.rarity = 'Common'
AND cr.set_code like '%lob%'
GROUP BY cd.id ORDER BY RAND() LIMIT 8) -- Set this limit to 8
) AS t LIMIT 9 -- then take first 9
编辑:更新了它,因为我以前的版本仍然可能失败并且 return 只有 8 个结果
然后,如果您需要按照原始查询的特定顺序反转 PHP 中的数组