问题
I am creating a view that needs to select only one random row for each customer. Something like:
select c.name, p.number
from customers c, phone_numbers p
where p.customer_id = c.id
If this query returns:
NAME NUMBER
--------- ------
Customer1 1
Customer1 2
Customer1 3
Customer2 4
Customer2 5
Customer3 6
I need it to be something like:
NAME NUMBER
--------- ------
Customer1 1
Customer2 4
Customer3 6
Rownum wont work because it will select only the first from all 6 records, and i need the first from each customer. I need solution that won't affect performance much, because the query that selects the data is pretty complex, this is just an example to explain what I need. Thanks in advance.
回答1:
Use the ROW_NUMBER()
analytic function:
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
回答2:
You can use group by clause to return only one phone number:
select c.name, MAX(p.number) as phone
from customers c, phone_numbers p
where p.customer_id = c.id
group by c.name
回答3:
You can also use the min or max aggregate function with 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
isn't a valid column or alias name as it's a reserved word, so use your own real name of course).
If the phone number needs to be arbitrary rather than actually random, you can order by something else:
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;
You'll probably get the same number back for each customer each time, but not always, and data/stats/plan changes will affect which you see. It seems like you don't care though. But then, using a plain aggregate might work just as well for you, as in @under's answer.
If you're getting lots of columns from that random row, rather than just the phone number, MTO's subquery might be simpler; for one or two values I find this a bit clearer though.
来源:https://stackoverflow.com/questions/44648534/selecting-one-random-data-from-a-column-from-multiple-rows-in-oracle