我正在创建一个视图,需要为每个客户只选择一个随机行。类似的东西:
select c.name, p.number
from customers c, phone_numbers p
where p.customer_id = c.id
如果此查询返回:
NAME NUMBER
--------- ------
Customer1 1
Customer1 2
Customer1 3
Customer2 4
Customer2 5
Customer3 6
我需要它像:
NAME NUMBER
--------- ------
Customer1 1
Customer2 4
Customer3 6
Rownum不会工作,因为它只会从所有6条记录中选择第一条记录,而我需要每个客户的第一条记录。我需要的解决方案不会对性能产生太大影响,因为选择数据的查询非常复杂,这只是解释我需要的一个例子。提前谢谢。
答案 0 :(得分:1)
使用ROW_NUMBER()
分析函数:
SELECT name,
number
FROM (
SELECT c.name,
p.number,
ROW_NUMBER() OVER ( PARTITION BY c.id ORDER BY DBMS_RANDOM.VALUE ) AS rn
FROM customers c
INNER JOIN phone_numbers p
ON ( p.customer_id = c.id )
)
WHERE rn = 1
答案 1 :(得分:1)
您可以使用group by子句只返回一个电话号码:
select c.name, MAX(p.number) as phone
from customers c, phone_numbers p
where p.customer_id = c.id
group by c.name
答案 2 :(得分:1)
您还可以将最小或最大聚合函数与the keep dense_rank
syntax:
select c.name,
min(p.number) keep (dense_rank last order by dbms_random.value) as number
from customers c
join phone_numbers p on p.customer_id = c.id
group by c.id, c.name
order by c.name;
(number
不是有效的列或别名,因为它是一个保留字,所以当然请使用您自己的真实姓名。)
如果电话号码需要是任意的而不是实际随机的,您可以通过其他方式订购:
select c.name,
min(p.number) keep (dense_rank last order by null) as number
from customers c
join phone_numbers p on p.customer_id = c.id
group by c.id, c.name
order by c.name;
您可能每次都会为每个客户返回相同的号码,但并非总是如此,数据/统计/计划更改会影响您看到的内容。看起来你似乎并不在乎。但是,使用普通聚合对你来说也可能同样有效,就像在@答案中一样。
如果您从该随机行中获取大量列,而不仅仅是电话号码,则MTO的子查询可能更简单;对于一个或两个值,我发现这更清楚了。