SQL - 抑制重复*相邻*记录

时间:2010-04-15 13:51:11

标签: sql db2

我需要运行一个Select语句(DB2 SQL),它不会根据某个字段提取相邻的行重复项。具体来说,我试图找出数据更改的时间,这很难,因为它可能会更改回原始值。

也就是说,我有一张模糊地类似于下面的表格,按字母排序,然后按日期排序:

A, 5, 2009-01-01
A, 12, 2009-02-01
A, 12, 2009-03-01
A, 12, 2009-04-01
A, 9, 2009-05-01
A, 9, 2009-06-01
A, 5, 2009-07-01

我想得到结果:

A, 5, 2009-01-01
A, 12, 2009-02-01
A, 9, 2009-05-01
A, 5, 2009-07-01

丢弃相邻的重复项但保留最后一行(尽管它与第一行的编号相同)。显而易见:

Select Letter, Number, Min(Update_Date) from Table group by Letter, Number 

不起作用 - 它不包括最后一行。

编辑:由于似乎存在一些混淆,我已将月份列澄清到日期列中。它被认为是一种人类可以解析的简短形式,而不是实际的有效数据。

编辑:最后一行并不重要,因为它是最后一行,但因为它有一个“新值”,也是一个“旧值”。按NUMBER分组会将其包装在第一行;它需要保持独立的实体。

5 个答案:

答案 0 :(得分:3)

根据您所使用的DB2,有一些分析函数可以轻松解决此问题。下面是Oracle中的一个示例,但select语法看起来非常相似。

create table t1 (c1 char, c2 number, c3 date);

insert into t1 VALUES ('A', 5, DATE '2009-01-01');
insert into t1 VALUES ('A', 12, DATE '2009-02-01');
insert into t1 VALUES ('A', 12, DATE '2009-03-01');
insert into t1 VALUES ('A', 12, DATE '2009-04-01');
insert into t1 VALUES ('A', 9, DATE '2009-05-01');
insert into t1 VALUES ('A', 9, DATE '2009-06-01');
insert into t1 VALUES ('A', 5, DATE '2009-07-01');

SQL> l
  1  SELECT C1, C2, C3
  2    FROM (SELECT C1, C2, C3,
  3                 LAG(C2) OVER (PARTITION BY C1 ORDER BY C3) AS PRIOR_C2,
  4                 LEAD(C2) OVER (PARTITION BY C1 ORDER BY C3) AS NEXT_C2
  5            FROM T1
  6         )
  7   WHERE C2 <> PRIOR_C2
  8      OR PRIOR_C2 IS NULL -- to pick up the first value
  9   ORDER BY C1, C3
SQL> /

C         C2 C3
- ---------- -------------------
A          5 2009-01-01 00:00:00
A         12 2009-02-01 00:00:00
A          9 2009-05-01 00:00:00
A          5 2009-07-01 00:00:00

答案 1 :(得分:1)

基于设置的命令(即分组依据等)无法实现这一点。

您可以使用游标执行此操作。

就个人而言,我会将数据存入我的客户端应用程序并在那里进行过滤。

答案 2 :(得分:1)

您需要做的第一件事是确定您希望查看/考虑数据的顺序。 “Jan,Feb,Mar”的值无济于事,因为数据不按字母顺序排列。当你从12月翻转到1月时会发生什么?第1步:确定一个序列,该序列唯一地定义了与您的问题相关的每一行。

接下来,您必须能够将项目#x与项目#x-1进行比较,以查看它是否已更改。如果改变,包括;如果没有改变,排除。使用过程代码循环(SQL中的游标)时很简单,但是你想要使用它们吗?他们往往表现得不太好。

一种基于SQL的方法是将表连接到自身,join子句为“MyTable.SequenceVal = MyTable.SequenceVal - 1”。进行比较,确保你没有抛出集合的第一行(没有x-1),你就完成了。请注意,如果未对“SequenceVal”编制索引,性能可能会很糟糕。

答案 3 :(得分:0)

  

丢弃相邻的副本但是   保持最后一排。

为什么要保留最后一排?目的是什么?

答案 4 :(得分:0)

使用“EXCEPT”子句是一种方法。请参阅下面的解决方案。我已在此处包含了所有测试步骤。首先,我创建了一个会话表(在我与数据库断开连接后会消失)。

CREATE TABLE session.sample (
   letter CHAR(1),
   number INT,
   update_date DATE
);   

然后我导入了您的示例数据:

IMPORT FROM sample.csv OF DEL INSERT INTO session.sample;

验证您的样本信息在数据库中:

SELECT * FROM session.sample;

 LETTER NUMBER      UPDATE_DATE
 ------ ----------- -----------
 A                5 01/01/2009
 A               12 02/01/2009
 A               12 03/01/2009
 A               12 04/01/2009
 A                9 05/01/2009
 A                9 06/01/2009
 A                5 07/01/2009

   7 record(s) selected.

我用EXCEPT子句写了这个,并使用“WITH”来试图让它更清晰。基本上,我正在尝试选择具有前一个日期条目的所有行。然后,我从整个表中的select中排除所有这些行。

WITH rows_with_previous AS (
  SELECT s.*
  FROM session.sample s
  JOIN session.sample s2
    ON s.letter = s2.letter
      AND s.number = s2.number
      AND s.update_date = s2.update_date - 1 MONTH
)
SELECT *
FROM session.sample
EXCEPT ALL
SELECT *
FROM rows_with_previous;       

结果如下:

 LETTER NUMBER      UPDATE_DATE
 ------ ----------- -----------
 A                5 01/01/2009
 A               12 04/01/2009
 A                9 06/01/2009
 A                5 07/01/2009

   4 record(s) selected.