如何在PostgreSQL中使用SELECT DISTINCT和RANDOM()函数?

时间:2012-07-09 18:51:11

标签: sql postgresql select

我正在尝试运行SQL查询以获取四个随机项。由于表product_filterproduct中有多个touple,我必须在DISTINCT中使用SELECT,所以我收到此错误:

对于SELECT DISTINCT,

,ORDER BY表达式必须出现在选择列表中

但如果我将RANDOM()放入我的SELECT,则会避免DISTINCT结果。

有人知道如何将DISTINCTRANDOM()功能一起使用?以下是我有问题的查询。

SELECT DISTINCT
    p.id, 
    p.title
FROM
    product_filter pf
    JOIN product p ON pf.cod_product = p.cod
    JOIN filters f ON pf.cod_filter = f.cod
WHERE
    p.visible = TRUE
LIMIT 4
ORDER BY RANDOM();

5 个答案:

答案 0 :(得分:4)

你要么做一个子查询

SELECT * FROM (
    SELECT DISTINCT p.cod, p.title ... JOIN... WHERE
    ) ORDER BY RANDOM() LIMIT 4;

或者您尝试对这些相同的字段进行GROUPing:

SELECT p.cod, p.title, MIN(RANDOM()) AS o FROM ... JOIN ...
    WHERE ... GROUP BY p.cod, p.title ORDER BY o LIMIT 4;

两个表达式中哪一个会更快地评估取决于表结构和索引;通过对cod和title进行适当的索引,子查询版本将运行得更快(cod和title将取自索引基数信息,而cod是JOIN所需的唯一键,所以如果你按标题索引,cod和visible(用于WHERE),很可能根本不会访问物理表。

我不太确定第二个表达式是否会发生这种情况。

答案 1 :(得分:3)

您可以简化查询以避免先验问题:

SELECT p.cod, p.title
FROM   product p
WHERE  p.visible
AND    EXISTS (
    SELECT 1
    FROM   product_filter pf
    JOIN   filters f ON f.cod = pf.cod_filter
    WHERE  pf.cod_product = p.cod
    )
ORDER  BY random()
LIMIT  4;

主要观点:

  • 结果中只有表product中的列,其他表仅检查是否存在匹配的行。对于这样的情况, EXISTS semi-join 可能是最快最简单的解决方案。使用它不会使基表product中的行成倍增加,因此您无需再次使用DISTINCT删除它们。

  • LIMIT必须在ORDER BY后完成。

  • 我将p.visible = 't'简化为p.visible,因为 应该是布尔列。

答案 2 :(得分:0)

我认为你需要一个子查询:

select *
from (select DISTINCT p.cod, p.title
      from product_filter pf  join
           product p
           on pf.cod_product = p.cod
      where p.visible = 't'
     ) t
LIMIT 4
order by RANDOM()

首先计算不同的值,然后执行限制。

请注意,这确实会影响性能,因为在选择所需内容之前,此查询会对所有内容执行不同的操作。这是否重要取决于您的表的大小以及您如何使用查询。

答案 3 :(得分:0)

SELECT DISTINCT U.* FROM
(

    SELECT p.cod, p.title FROM product__filter pf

      JOIN product p on pf.cod_product = p.cod
      JOIN filters f on pf.cod_filter = f.cod

    WHERE p.visible = 't' 

    ORDER BY RANDOM()

) AS U

LIMIT 4

然后首先是RANDOM,然后是LIMIT。

答案 4 :(得分:0)

使用子查询。不要忘记表别名tLIMITORDER BY之后。

    SELECT *
    FROM (SELECT DISTINCT a, b, c
          FROM datatable WHERE a = 'hello'
         ) t
    ORDER BY random()
    LIMIT 10;