Selecting one random data from a column from multiple rows in oracle

坚强是说给别人听的谎言 提交于 2020-01-17 08:21:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!