在Oracle中,如何从排序结果中获取不同值的页面?

时间:2012-03-30 20:39:21

标签: sql oracle

我在一对多关系中有两列。我想对“很多”进行排序并返回第一次出现的“one”。我需要翻阅数据,所以,例如,我需要能够获得第3组10个唯一的“一”值。

我有这样的查询:

SELECT id, name
FROM table1
INNER JOIN table2 ON table2.fkid = table1.id
ORDER BY name, id;

table1中每行可以有多行。

我的查询结果如下:

  id   |  name
----------------
   2   | apple
  23   | banana
  77   | cranberry
  23   | dark chocolate
   8   | egg
   2   | yak
  19   | zebra

我需要在每个包含n 唯一 ID的页面中翻阅结果集。例如,如果start = 1且n = 4,我想回来

 2
23
77
 8

按照它们的排序顺序(即名称),其中id在第一次出现的位置返回。同样,如果start = 3且n = 4并且order = desc我想要

 8
23
77
 2

我试过了:

SELECT * FROM (
  SELECT id, ROWNUM rnum FROM (
    SELECT DISTINCT id FROM (
      SELECT id, name
      FROM table1
      INNER JOIN table2 ON table2.fkid = table1.id
      ORDER BY name, id)
    WHERE ROWNUM <= 4)
  WHERE rnum >=1)

以数字顺序给出了id,而不是按名称命令。

我也尝试过:

SELECT * FROM (
  SELECT DISTINCT id, ROWNUM rnum FROM (
    SELECT id FROM (
      SELECT id, name
      FROM table1
      INNER JOIN table2 ON table2.fkid = table1.id
      ORDER BY name, id)
    WHERE ROWNUM <= 4)
  WHERE rnum >=1)

但这给了我重复的值。

如何浏览此数据的结果?我只需要ids,而不是“很多”表。

更新

我想我正在接近将内部查询更改为

SELECT id, name, rank() over (order by name, id)
FROM table1
INNER JOIN table2 ON table2.fkid = table1.id

...但我仍然会收到重复的ID。

2 个答案:

答案 0 :(得分:1)

您可能需要稍微调试一下,但它会是这样的:

  SELECT * FROM (
   SELECT * FROM (
    SELECT id FROM (
      SELECT id, name, row_number() over (partition by id order by name) rn
      FROM table1
      INNER JOIN table2 ON table2.fkid = table1.id
      )
   ) WHERE rn=1 ORDER BY name, id
  ) WHERE rownum>=1 and rownum<=4;

答案 1 :(得分:0)

这有点令人费解(我倾向于怀疑它可以简化)但它应该有效。你可以在WHERE子句中放置你想要的任何开始和结束位置 - 我在这里展示的是start = 2和n = 4是从一个单独的表中提取的,但是你可以通过使用一对来简化事情而是参数。

SQL> ed
Wrote file afiedt.buf

  1  with t as (
  2    select 2 id, 'apple' name from dual union all
  3    select 23, 'banana' from dual union all
  4    select 77, 'cranberry' from dual union all
  5    select 23, 'dark chocolate' from dual union all
  6    select 8, 'egg' from dual union all
  7    select 2, 'yak' from dual union all
  8    select 19, 'zebra' from dual
  9  ),
 10  x as (
 11    select 2 start_pos, 4 n from dual
 12  )
 13  select *
 14    from (
 15      select distinct
 16             id,
 17             dense_rank() over (order by min_id_rnk) outer_rnk
 18        from (
 19          select id,
 20                 min(rnk) over (partition by id) min_id_rnk
 21            from (
 22              select id,
 23                     name,
 24                     rank() over (order by name) rnk
 25                from t
 26             )
 27        )
 28    )
 29   where outer_rnk between (select start_pos from x) and (select start_pos+n-1 from x)
 30*  order by outer_rnk
SQL> /

        ID  OUTER_RNK
---------- ----------
        23          2
        77          3
         8          4
        19          5