过滤掉SELECT中的重复后续记录

den*_*kai 6 sql postgresql window-functions gaps-and-islands

(PostgreSQL 8.4) 表"trackingMessages"存储移动设备(tm_nl_mobileid)和固定设备(tm_nl_fixedId)之间的跟踪事件.

CREATE TABLE trackingMessages
(
  tm_id SERIAL PRIMARY KEY,           -- PK
  tm_nl_mobileId INTEGER,             -- FK to mobile
  tm_nl_fixedId INTEGER,              -- FK to fixed
  tm_date INTEGER,                    -- Network time
  tm_messageType INTEGER,             -- 0=disconnect, 1=connect
  CONSTRAINT tm_unique_row
    UNIQUE (tm_nl_mobileId, tm_nl_fixedId, tm_date, tm_messageType)
);
Run Code Online (Sandbox Code Playgroud)

这里的问题是,相同的移动设备可能随后连接到相同的固定设备两次(或更多次).我不希望看到后续的那些,但是可以看到移动设备在以后固定连接到同一个固定设备,前提是它们之间存在连接到不同的固定设备.

我想我很亲密但并不完全.我一直在使用以下CTE(在Stack Overflow上找到)

WITH cte AS 
(
  SELECT tm_nl_fixedid, tm_date, Row_number() OVER (
    partition BY tm_nl_fixedid
    ORDER BY tm_date ASC
  ) RN 
  FROM   trackingMessages
) 
SELECT * FROM cte 
  WHERE tm_nl_mobileid = 150 AND tm_messagetype = 1
  ORDER BY tm_date;
Run Code Online (Sandbox Code Playgroud)

给我以下结果

32;1316538756;1
21;1316539069;1
32;1316539194;2
32;1316539221;3
21;1316539235;2
Run Code Online (Sandbox Code Playgroud)

这里的问题是最后一列应该是1,1,1,2,1,因为第三个"32"实际上是一个重复的跟踪事件(在同一个固定的行中连续两次)并且最后一个连接到"21" "很好,因为"32"介于两者之间.

请不要建议光标,这是我目前正试图摆脱的.游标解决方案确实有效,但考虑到我必须处理的记录数量,它太慢了.我宁愿修理CTE而只选择哪里RN = 1......除非你有更好的主意!

Nik*_*vić 5

好吧,你不是那么接近,因为row_number()无法同时跟踪两组的序列.PARTITION BY tm_nl_fixedid ORDER BY date RESTART ON GAP不存在,没有这样的事情.

Itzik Ben-Gan为您所面临的岛屿和间隙问题提供了解决方案(实际上有几种解决方案).我们的想法是按主要标准(日期)排序行,然后按分区标准+主要标准排序.序数之间的差异将保持相同,因为它们属于相同的分区标准和日期系列.

with cte as
(
  select *,
      -- While order by date and order by something-else, date
      -- run along, they belong to the same sequence
         row_number() over (order by tm_date)
       - row_number() over (order by tm_nl_fixedid, tm_date) grp
    from trackingMessages
)
select *,
    -- Now we can get ordinal number grouped by each sequence
       row_number() over (partition by tm_nl_fixedid, grp
                          order by tm_date) rn
  from cte
 order by tm_date
Run Code Online (Sandbox Code Playgroud)

这是Sql Fiddle的例子.

这里是Sql Server MVP Deep Dives的第5章,其中包含几个岛屿和间隙问题的解决方案.