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

ここでの問題は、同じモバイルが同じ固定電話に 2 回 (またはそれ以上) 接続する可能性があることです。後続のものは見たくありませんが、間に別の固定への接続があった場合は、後で同じ固定に接続されたモバイルが表示されても問題ありません。

私は近いと思いますが、完全ではありません。私は次のCTEを使用しています(スタックオーバーフローでここにあります)

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 でなければならないことです。これは、3 番目の「32」が実際には重複した追跡イベント (同じ固定で 2 回続けて) であり、「21」への最後の接続であるためです。 「32」が間にあったのでOKです。

カーソルを提案しないでください。これは私が現在離れようとしているものです。カーソル ソリューションは機能しますが、処理しなければならないレコードの量を考えると遅すぎます。CTE を修正して、場所だけを選択したいのですがRN = 1...もっと良いアイデアがない限り!

4

2 に答える 2

6

ええと、row_number()2 つのグループで同時にシーケンスを追跡することはできないため、それほど近くにはありません。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 に答える