0

我有一个包含三个字段的表IDdateaction。的三个可能值actionX和。我想要一个查询,对于表中的每个有一个操作的行,如果存在一个操作,它将返回与操作相同的最新行。YZIDZIDX

这是我想在 MySQL 中做的事情。我从sqlfiddle.com复制并粘贴了代码,所以我知道它有效。

create table a (id int,
              date int,
              action varchar(1));

insert into a values(1, 1, 'X');
insert into a values(1, 2, 'X');
insert into a values(1, 3, 'Z');
insert into a values(2, 1, 'X');
insert into a values(2, 2, 'Y');
insert into a values(2, 3, 'Y');
insert into a values(2, 4, 'Z');
insert into a values(3, 1, 'X');
insert into a values(3, 2, 'Y');
insert into a values(3, 3, 'X');
insert into a values(3, 4, 'Z');
insert into a values(4, 3, 'X');


SELECT a.id,
       max(a.date) as Xdate,
       b.date as Zdate,
       a.action FROM a,

               (SELECT * FROM a WHERE a.action = 'Z') b
                WHERE
                    a.date < b.date AND
                    a.ID = b.ID AND
                    a.action = 'X'
                GROUP BY a.id;

我不能GROUP BY在 Oracle 中将此子句与其他字段一起使用,所以我做了一个嵌套子查询,分别找到每个 ID 的最大日期,但它非常慢(我预计会得到大约 10^5 行)而且我希望有更好的方法可以更快地做到这一点。(我目前无法发布我的实际 Oracle 查询,因为它不在 SQLfiddle 中运行;它一直抱怨行的定义不明确。)

可以使上述查询以某种方式在 Oracle 中工作吗?如果没有,是否有等效的方法可以在合理的时间内运行?

4

3 回答 3

2

这有效(尽管它可能能够被简化):

SELECT a.id,
       max(a."date") as Xdate,
       b."date" as Zdate,
       a.action 
FROM a INNER JOIN 
  (SELECT * 
   FROM a 
   WHERE a.action = 'Z') b
  ON a.ID = b.ID 
WHERE a."date" < b."date" 
   AND a.action = 'X'
GROUP BY a.id, b."date", a.action

请注意,您需要使用"保留字 - 在这种情况下为 column date。您还需要将所有字段添加到GROUP BY子句中。MySQL 允许它没有,但 Oracle 不允许。


编辑,简化版本:

SELECT a.Id, max(a."date"), b."date", a.action
FROM a
  INNER JOIN a b ON a.Id = b.Id AND b.action = 'Z'
WHERE a.action = 'X' 
  AND a."date" < b."date"
GROUP BY a.Id, b."date", a.action
于 2013-07-21T02:23:49.923 回答
1

这里的其他解决方案:

WITH temp AS (
     SELECT a.id, a.date_f, a.action FROM a WHERE a.action = 'Z'
)
SELECT a.id,
       max(a.date_f) as Xdate,
       temp.date_f as Zdate,
       a.action
FROM a
INNER JOIN temp ON temp.id = a.id AND a.date_f < temp.date_f
WHERE a.action = 'X'
GROUP BY a.id,temp.date_f,a.action;

注意:date_f 是字段日期。 SQL 小提琴演示

于 2013-07-21T02:33:34.267 回答
0

试图在 MySQL 和 Oracle 之间切换的一个问题是 Oracle 更强大。

您可以使用 Oracle 中的分析函数来解决您的问题。这些在 MySQL 中不可用。

这是 Oracle 解决方案:

select a.id, a.thedate as Xdate, a.ZDate
from (select a.*,
             min(case when action = 'Z' then thedate end) over
                 (partition by id
                  order by thedate
                  rows between current row and unbounded following
                 ) as Zdate,
             row_number() over (partition by id, action
                                order by thedate desc
                               ) as seqnum
      from a
     ) a
where a.action = 'X' and a.seqnum = 1;

您可以在此处的 SQL Fiddle 上看到它。

于 2013-07-21T13:08:41.797 回答