6

(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)
);

这里的问题是,同一台手机可能随后会连接到同一台固定设备两次(或更多次)。我不想看到后面的那些,但是可以在以后看到移动设备连接到同一个固定设备,前提是两者之间有不同的固定设备连接。

我想我很接近但不完全。我一直在使用以下 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;

给我以下结果

32;1316538756;1
21;1316539069;1
32;1316539194;2
32;1316539221;3
21;1316539235;2

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

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

4

2 回答 2

6

好吧,您并没有那么接近,因为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

这是带有示例的 Sql Fiddle

这是 Sql Server MVP Deep Dives 的第 5 章,其中包含一些解决孤岛和间隙问题的方法。

于 2012-09-16T23:45:05.450 回答
3

使用窗口函数lag()应该更简单:

WITH cte AS (
   SELECT *
         ,lag(tm_nl_fixedId) OVER (PARTITION BY tm_nl_mobileId
                                   ORDER BY tm_date) AS last_fixed
   FROM   trackingmessages
   )
SELECT *
FROM   cte
WHERE  last_fixed IS DISTINCT FROM tm_nl_fixedId
ORDER  BY tm_date

解释

  • 在 CTE 中,lag()获取移动设备连接的最后一个固定设备(NULL对于每个移动设备的第一行 - 这就是我IS DISTINCT FROM稍后使用的原因,请在此处查看不同的方法)。

  • 然后简单地排除最后一个固定设备与该设备相同的所有行,从而排除所有“后续设备”。全部做完。

于 2012-09-17T23:51:15.513 回答