(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
...除非你有更好的想法!
答案 0 :(得分: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
答案 1 :(得分:3)
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
的原因,请参阅一种不同的方法here)。
然后简单地排除最后一个固定设备与此相同的所有行,从而排除所有“后续的”。全部完成。