我正在尝试运行SQL查询以获取四个随机项。由于表product_filter
在product
中有多个touple,我必须在DISTINCT
中使用SELECT
,所以我收到此错误:
,ORDER BY表达式必须出现在选择列表中
但如果我将RANDOM()
放入我的SELECT
,则会避免DISTINCT
结果。
有人知道如何将DISTINCT
与RANDOM()
功能一起使用?以下是我有问题的查询。
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();
答案 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)
使用子查询。不要忘记表别名t
。 LIMIT
在ORDER BY
之后。
SELECT *
FROM (SELECT DISTINCT a, b, c
FROM datatable WHERE a = 'hello'
) t
ORDER BY random()
LIMIT 10;