我需要运行一个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分组会将其包装在第一行;它需要保持独立的实体。
答案 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.