如何筛选复杂过滤器上的行

时间:2010-06-09 20:01:32

标签: sql oracle

我在表格中有这些行

ID  Name    Price   Delivery
==  ====    =====   ========
1   apple   1       1
2   apple   3       2
3   apple   6       3
4   apple   9       4
5   orange  4       6
6   orange  5       7

如果没有第三次交货,我希望第三次交货(交货= 3)或最后价格。

它会给我这个:

ID  Name    Price   Delivery
==  ====    =====   ========
3   apple   6       3
6   orange  5       7

我没有必要想要一个完整的解决方案,但我们将非常感谢您对寻找什么的想法。

4 个答案:

答案 0 :(得分:4)

SQL> create table t (id,name,price,delivery)
  2  as
  3  select 1, 'apple', 1, 1 from dual union all
  4  select 2, 'apple', 3, 2 from dual union all
  5  select 3, 'apple', 6, 3 from dual union all
  6  select 4, 'apple', 9, 4 from dual union all
  7  select 5, 'orange', 4, 6 from dual union all
  8  select 6, 'orange', 5, 7 from dual
  9  /

Table created.

SQL> select max(id) keep (dense_rank last order by nullif(delivery,3) nulls last) id
  2       , name
  3       , max(price) keep (dense_rank last order by nullif(delivery,3) nulls last) price
  4       , max(delivery) keep (dense_rank last order by nullif(delivery,3) nulls last) delivery
  5    from t
  6   group by name
  7  /

        ID NAME        PRICE   DELIVERY
---------- ------ ---------- ----------
         3 apple           6          3
         6 orange          5          7

2 rows selected.

编辑:由于您想要“了解要查找的内容”,以下是对我认为此解决方案最佳的原因的说明,此外还有最少行的查询。您的预期结果集表示您要按水果名称对数据进行分组(“按名称分组”)。并且,对于每个组,您希望保留记录的值为delivery = 3,或者当该数字不存在时,最后一个(“keep(dense_rank last order by nullif(delivery,3)nulls lasts”)。在我的看来,上面的查询就是这样的。它只使用一个表访问来获得结果,尽管我的查询并不是唯一的。

此致 罗布。

答案 1 :(得分:3)

使用ROW_NUMBER两次 - 一次过滤第三次传递之后的行,第二次查找剩余的最后一行(即每组查询的典型最大值)。

我使用CTE实现了这一点。我在SQL Server中测试过,但我相信Oracle支持相同的语法。

WITH T1 AS (
    SELECT
        ID, Name, Price, Delivery,
        ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Delivery) AS rn
    FROM Table1
), T2 AS (
    SELECT
        t1.*,
        ROW_NUMBER() OVER (PARTITION BY Name ORDER BY Delivery DESC) AS rn2
    FROM T1
    WHERE rn <= 3
)
SELECT ID, Name, Price, Delivery
FROM T2
WHERE rn2 = 1

结果:

ID  Name    Price  Delivery
3   apple   6      3       
6   orange  5      7       

答案 2 :(得分:2)

select t3.ID, t3.Name, t3.Price, t3.Delivery
from  (
    select Name, max(Delivery) as MaxDelivery
    from MyTable
    group by Name
) t1
left outer join MyTable t2 on t1.Name = t2.Name and Delivery = 3
inner join MyTable t3 on t1.Name = t3.name 
    and t3.Delivery = coalesce(t2.Delivery, t1.MaxDelivery)

答案 3 :(得分:2)

如果您的意思是第三次交付,马克和APC的答案都有效,无论交货编号如何。这是一个使用分析函数的解决方案,专门搜索Delivery = 3的记录。

CREATE TABLE FRUITS (
    ID NUMBER,
    Name VARCHAR2(10),
    Price INTEGER,
    Delivery INTEGER);

INSERT INTO FRUITS VALUES (1, 'apple', 1, 1);
INSERT INTO FRUITS VALUES (2, 'apple', 3, 2);
INSERT INTO FRUITS VALUES (3, 'apple', 6, 3);
INSERT INTO FRUITS VALUES (4, 'apple', 9, 4);
INSERT INTO FRUITS VALUES (5, 'orange', 4, 6);
INSERT INTO FRUITS VALUES (6, 'orange', 5, 7);
INSERT INTO FRUITS VALUES (7, 'pear', 2, 5);
INSERT INTO FRUITS VALUES (8, 'pear', 4, 6);
INSERT INTO FRUITS VALUES (9, 'pear', 6, 7);
INSERT INTO FRUITS VALUES (10, 'pear', 8, 8);

SELECT ID,
       Name,
       Price,
       Delivery
  FROM (SELECT ID,
               Name,
               Price,
               Delivery,
               SUM(CASE WHEN Delivery = 3 THEN 1 ELSE 0 END) 
                   OVER (PARTITION BY Name) AS ThreeCount,
               ROW_NUMBER()
                   OVER (PARTITION BY Name ORDER BY Delivery DESC) AS rn
          FROM FRUITS)
 WHERE (ThreeCount <> 0 AND Delivery = 3) OR
       (ThreeCount = 0 AND rn = 1)
ORDER BY ID;

DROP TABLE FRUITS;

Oracle XE 10g的结果:

ID   Name       Price   Delivery  
---- ---------- ------- ----------
3    apple      6       3         
6    orange     5       7         
10   pear       8       8         

我在样本数据中加入了第三个水果,以说明对问题的不同解释的影响。其他解决方案将为梨选择ID = 9。