在子查询中选择上次更改的行

时间:2014-12-19 09:34:37

标签: sql oracle select

我有一个表产品

id | owner_id | last_activity | box_id
------------------------------------
1  |     2    | 12/19/2014    | null
2  |     2    | 12/13/2014    | null
3  |     2    | 08/11/2014    | null
4  |     2    | 12/11/2014    | 99
5  |     2    | null          | 99
6  |     2    | 12/15/2014    | 99
7  |     2    | null          | 105
8  |     2    | null          | 105
9  |     2    | null          | 105

我唯一的变量是 owner_id 。 我需要选择用户的所有产品,但如果产品在一个盒子中,那么只应该选择最新的产品。

owner = 2的示例输出如下:

id | owner_id | last_activity | box_id
------------------------------------
1  |     2    | 12/19/2014    | null
2  |     2    | 12/13/2014    | null
3  |     2    | 08/11/2014    | null
6  |     2    | 12/15/2014    | 99
7  |     2    | null          | 105

我无法找到从盒子中选择最新产品的方法。

我当前的查询,它不会返回正确的值,但可以执行:

SELECT p.* FROM product p
WHERE p.owner_id = 2
AND (
  p.box IS NULL
  OR (
    p.box IS NOT NULL
    AND
    p.id = ( SELECT MAX(pp.id) FROM product pp
             WHERE pp.box_id = p.box_id )
  )

我尝试过日期:

SELECT p.* FROM product p
WHERE p.owner_id = 2
AND (
  p.box IS NULL
  OR (
    p.box IS NOT NULL
    AND
    p.id = ( SELECT * FROM (
              SELECT pp.id FROM product pp
              WHERE pp.box_id = p.box_id 
              ORDER BY last_activity desc
            ) WHERE rownum = 1
           )
  )

哪个错误: p.box_id 未定义,因为它在第二个子查询中。

您有什么想法我该如何解决?

3 个答案:

答案 0 :(得分:0)

使用存在

SELECT
  p.*
FROM
  product p
WHERE
  p.owner_id = 2 AND
  ( p.box IS NULL OR
    (
      p.box IS NOT NULL AND
      NOT EXISTS
      (
        SELECT
          pp.id
        FROM
          product pp
        WHERE
          pp.box_id = p.box_id AND
          pp.last_activity > p.last_activity
      )
    )
  )

答案 1 :(得分:0)

你可以使用union来获取box_is为null的所有行,而不是获取具有最大id和日期的行,其中box_id不为null:

SELECT * FROM
(
   SELECT id,owner_id,last_activity,box_id FROM product WHERE owner_id = 2 AND box_id IS NULL
   UNION
   SELECT MAX(id),owner_id,MAX(last_activity),box_id FROM product WHERE owner_id = 2 AND box_id IS NOT    NULL GROUP BY owner_id, box_id 
) T1
ORDER BY
    id

答案 2 :(得分:0)

ROW_NUMBER分析函数可能有助于此类查询:

SELECT  "owner_id", "id", "box_id", "last_activity" FROM
(

    SELECT "owner_id", "id", "box_id", "last_activity",
           ROW_NUMBER() 
            OVER (PARTITION BY "box_id" ORDER BY "last_activity" DESC NULLS LAST) rn
            --                                                   ^^^^^^^^^^^^^^^
            --               descending order, reject nulls after not null values
            --                                 (this is the default, but making it
            --                                  explicit here for self-documentation
            --                                  purpose)
    FROM T
    WHERE "owner_id" = 2

) V
WHERE rn = 1 or "box_id" IS NULL
ORDER BY "id" -- <-- probably not necessary, but matches your example

请参阅http://sqlfiddle.com/#!4/db775/8


  

可以将null作为值。如果框内的所有产品都有空值,则应返回MIN(id)

即使可能依靠id来订购内容的好主意,您认为需要这样做,您必须将ORDER BY条款更改为:

... ORDER BY "last_activity" DESC NULLS LAST, "id" DESC
--                                          ^^^^^^^^^^^