【问题标题】:SQL select: random order values from one table for each row in anotherSQL select:一个表中的随机顺序值用于另一个表中的每一行
【发布时间】:2012-07-05 15:23:17
【问题描述】:

我的数据库中有两个表:

(1) 短语:

t_phrase
========
I like
They prefer
...
Somebody else wants

(2) 地点:

n_id   t_place
====   =======
1      London
2      Paris
...
N      New York

PHRASES 的行数至少与PLACES 一样多。我需要以这样一种方式加入这两个表,以便为每个表选择所有 places 和一个 phrase - 但短语需要随机分布在不同的地方。整个places 表并不太大:可能大约有 3 到 4 千行,但是上面会有一个额外的 WHERE 子句,最多会将输出限制为大约 200 个位置。

理想情况下,我希望它包含在一个 SQL 语句中,但到目前为止,我还无法理解这一点。因此,第二个选项是返回一行(int, varchar, varchar) 的存储函数。为此,我正在考虑以下内容:

  1. 以随机顺序选择所有短语到 varchar 数组中
  2. 循环遍历一次取一个的位置并将其与数组中的下一个短语一起返回

不知何故,这在我看来效率很低,但我想不出更好的办法。

你能提出更好的主意吗?或者,更好的是,一个语句 SQL,也许?

提前致谢。

编辑:请注意,这些短语不应在结果集中重复。短语的数量总是至少与地点的数量一样多。

【问题讨论】:

    标签: sql postgresql stored-procedures stored-functions


    【解决方案1】:
    WITH p AS (
        SELECT place, row_number() OVER () AS rn
        FROM   t_place
        WHERE  <some condition>
        )
        , ph AS (
        SELECT phrase, row_number() OVER (ORDER BY random()) AS rn
        FROM   t_phrase
        )
    SELECT ph.phrase, p.place
    FROM   p
    JOIN   ph USING (rn);
    

    它不会再随机化了,如果你对两张表都施加真正的随机顺序,它只会变得更慢。我对短语施加随机顺序,因为:

    总是有多少地方就有多少短语。

    它需要用更大的集合来完成,以免一些非随机部分可能被切断。另一方面,对于较小的集合(地点),任何无间隙的数字序列都是好的,所以我选择最快的方法。

    我的示例使用 CTE,但也可以使用子查询来完成。 CTEwindow functions 都需要 PostgreSQL 8.4 或更高版本。

    【讨论】:

    • 是的,这行得通。不幸的是,live db 是 8.3,所以我不得不使用子查询。谢谢。
    【解决方案2】:

    我认为以下方法会起作用:

    select (select phrase from phrases order by random() limit 1),
           place
    from places
    

    应该为每一行调用select中的select,因此每次都应该返回不同的值。

    如果您只想随机排列短语和地点,可以使用 windows 功能:

    select ph.phrase, p.place
    from (select place, row_number() over (order by place) as seqnum
          from places p
         ) p join
         (select phrase, row_number() over (order by random()) as seqnum
          from phrases
         ) ph 
         on p.seqnum = ph.seqnum
    

    这会按地点(或任何字段都可以)对地点进行排序。它将短语随机化,并加入结果行号。

    【讨论】:

    • 这不起作用,因为它每次都会随机选择,从而可能导致重复的短语。
    • 我误会了。我以为你想要每个地方的随机短语。我会修改这个案例的解决方案。
    • 第一个示例的性能影响是什么?我担心的是,尽管有LIMIT 1,它仍然会为每个place 运行整个表(当然,这里的结果集不是很大,但是...)
    • 如果您对性能影响感兴趣,请查看:stackoverflow.com/questions/5297396/…。 postgres 每次都应该读取表没有先验的原因,但这取决于数据库实现者。
    • 是的,即使在我们过时的 8.3 上也能完美运行。谢谢!
    猜你喜欢
    • 2012-11-23
    • 2015-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多