使用连接时为每个不同的字段值选择随机行
Posted
技术标签:
【中文标题】使用连接时为每个不同的字段值选择随机行【英文标题】:Select random row per distinct field value while using joins 【发布时间】:2021-03-30 03:48:22 【问题描述】:我有一个显示一些帖子的 Wordpress 实例。每个帖子都以特定语言定义,并具有属性_post_year
集。所以我们可以有几篇文章使用相同的语言并引用同一年份。
mysql 表:
wp-posts
包含所有帖子。
ID | post_author | post_date | ...
==================================
1 | ...
2 | ...
...
wp_term_relationships
包含有关帖子语言的信息(除其他外)。
object_id | term_taxonomy_id | term_order |
===========================================
1 | ...
1 | ...
2 | ...
...
wp_postmeta
包含帖子元信息(如附加属性“_post_year”)。
meta_id | post_id | meta_key | meta_value |
===========================================
1 | 1 | ...
2 | 1 | ...
...
我曾经能够像这样加载每年一篇随机帖子(适用于所有可用年份):
SELECT DISTINCT
wp_posts.*,
postmeta.meta_value as post_meta_year
FROM (
SELECT * FROM wp_posts
JOIN wp_term_relationships as term_relationships
ON term_relationships.object_id = wp_posts.ID
AND term_relationships.term_taxonomy_id IN (LANGUAGE_ID)
ORDER BY RAND()
) as wp_posts
JOIN wp_postmeta as postmeta
ON postmeta.post_id = wp_posts.ID
AND postmeta.meta_key = '_post_year'
AND post_status = 'publish'
GROUP BY post_meta_year DESC
ORDER BY post_meta_year DESC
自从我将 MySQL 升级到 5.7 版后,这不再起作用了:
Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'wp_posts.ID' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
我怎样才能使每年的随机帖子按降序排列?
【问题讨论】:
只是为了观察,10 年后,我还不需要在同一个查询中提供 DISTINCT 和 GROUP BY 为什么要升级到 3 年以上的 MySQL 版本? 好问题@GordonLinoff :) 升级是在一年前完成的(除了 5.7 之外,还有其他更多的选项,老实说,我从来没有想过,但会问他们),但注意到了具体问题就在上周。 【参考方案1】:您可以尝试一种方法:从具有不同年份的派生表中选择年份,并在相关子查询中使用 ORDER BY rand()
和 LIMIT 1
选择具有该年份的随机帖子 ID。将第二个派生表的结果与帖子连接起来。
SELECT po1.*,
ppmo1.meta_value
FROM (SELECT pmo1.meta_value,
(SELECT pi1.id
FROM wp_posts pi1
INNER JOIN wp_postmeta pmi2
ON pmi2.post_id = pi1.id
INNER JOIN wp_term_relationships tri1
ON tri1.object_id = pi1.id
WHERE tri1.term_taxonomy_id = LANGUAGE_ID
AND pmi2.meta_key = '_post_year'
AND pmi2.meta_value = pmo1.meta_value
ORDER BY rand()
LIMIT 1) id
FROM (SELECT DISTINCT
pmi1.meta_value
FROM wp_postmeta pmi1
WHERE pmi1.meta_key = '_post_year') pmo1) ppmo1
INNER JOIN wp_posts po1
ON po1.id = ppmo1.id
ORDER BY ppmo1.meta_value DESC;
(未经测试,因为架构和示例数据不是由可消耗的 DDL 和 DML 提供的。)
【讨论】:
这非常有效。我在sqlfiddle.com/#!9/0e4c7d/4 创建了一个 sqlfiddle。谢谢@sticky-bit! 现在我试着绕过这个:)【参考方案2】:在 MySQL 5.7 中,ONLY_FULL_GROUP_BY
模式默认启用(很高兴),我建议使用相关子查询进行过滤:
select * -- better enumerate the actual column names here
from wp_posts p
inner join wp_postmeta pm on pm.post_id = p.id
where pm.meta_key = '_post_year' and p.id = (
select pm1.post_id
from wp_post p1
inner join wp_postmeta pm1 on pm1.post_id = p1.id
where p1.status = 'publish' and pm1.meta_key = '_post_year' and pm1.meta_value = pm.meta_value
order by rand() limit 1
)
基本上,子查询为每组具有相同'_post_year'
的记录选择一个随机的post id,用于过滤查询。
请注意,使用此技术,无需在外部查询中再次过滤帖子状态,因为子查询已经完成并返回主键列。
【讨论】:
嗨@GMB,谢谢你的回答。我在sqlfiddle.com/#!9/0e4c7d/1/0 创建了一个 sqlfiddle,我刚刚创建了所有表(抱歉之前没有这样做)并测试了您的查询。不幸的是,结果以一种无用的方式变化。有时此查询不止一次返回一年,有时一年根本不存在。以上是关于使用连接时为每个不同的字段值选择随机行的主要内容,如果未能解决你的问题,请参考以下文章
使用 sql (Hive) 中的条件为每个 ID 选择随机行
在 spark scala 中为数据帧中的每个组采样不同数量的随机行