3

私はこのロジックに従うクエリを書き込もうとしています:

以前のステータスコードがXであったアカウントの最初の次のステータスコードを見つけます。

したがって、次のテーブルがある場合:

id    account_num    status_code
64        1               X
82        1               Y
72        2               Y
87        1               Z
91        2               X
103       2               Z

結果は次のようになります。

id   account_num     status_code
82        1               Y
103       2               Z

私はいくつかの解決策を考え出しましたが、私はSQLにそれほど優れているわけではないので、これまでのところかなり無関心でした。私はここの誰かが私を正しい方向に向けることができるかもしれないことを望んでいました。

意見:

SELECT account_number, id
FROM   table
WHERE  status_code = 'X'

クエリ:

SELECT account_number, min(id)
FROM   table
INNER JOIN view
ON table.account_number = view.account_number
WHERE table.id > view.id

この時点で、必要なIDがありますが、そのIDを使用してstatus_codeを検索する別のクエリを作成する必要があります。

編集:コンテキストを追加するために、status_codeがXの呼び出しを見つけようとしています。呼び出しのstatus_codeがXの場合、次に試行するときに別の方法でダイヤルします。このクエリの目的は、最初のダイヤルがXステータスコードになった場合に2番目のダイヤルの結果を表示するレポートを提供することです。

4

4 に答える 4

2

これがSQLServerソリューションです。

アップデート

アイデアは、Olafによって提案された多数のNESTED LOOP結合を回避することです。これは、それらがおおよそO(N * M)の複雑さを持ち、パフォーマンスに非常に悪いためです。MERGED JOINSの複雑さはO(N Log(N)+ M Log(M))であり、実際のシナリオにはるかに適しています。

以下のクエリは次のように機能します。

RankedCTEアカウントで分割され、時間を表すidでソートされた各IDに行番号を割り当てるサブクエリです。したがって、この出力の下のデータについては

SELECT 
    id, 
    account_num, 
    status_code,
    ROW_NUMBER() OVER (PARTITION BY account_num ORDER BY id DESC) AS item_rank
FROM dbo.Test

だろう:

id          account_num status_code item_rank
----------- ----------- ----------- ----------
87          1           Z           1
82          1           Y           2
64          1           X           3
103         2           Z           1
91          2           X           2
72          2           Y           3

それらに番号を付けたら、次のように結果を結合します。

WITH RankedCTE AS
(
    SELECT 
        id, 
        account_num, 
        status_code,
        ROW_NUMBER() OVER (PARTITION BY account_num ORDER BY id DESC) AS item_rank
    FROM dbo.Test
)
SELECT 
    *
FROM
    RankedCTE A
    INNER JOIN RankedCTE B ON 
            A.account_num = B.account_num
            AND A.item_rank = B.item_rank - 1    

これにより、同じテーブル内のイベントと先行イベントが提供されます

id          account_num status_code item_rank   id          account_num status_code item_rank
----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
87          1           Z           1           82          1           Y           2
82          1           Y           2           64          1           X           3
103         2           Z           1           91          2           X           2
91          2           X           2           72          2           Y           3

最後に、コード「X」の前のイベントと「X」ではないコードのイベントを取得する必要があります。

    WITH RankedCTE AS
    (
        SELECT 
            id, 
            account_num, 
            status_code,
            ROW_NUMBER() OVER (PARTITION BY account_num ORDER BY id DESC) AS item_rank
        FROM dbo.Test
    )
    SELECT 
        A.id, 
        A.account_num, 
        A.status_code
    FROM 
        RankedCTE A
        INNER JOIN RankedCTE B ON 
            A.account_num = B.account_num
            AND A.item_rank = B.item_rank - 1
            AND A.status_code <> 'X'
            AND B.status_code = 'X'

このクエリのクエリプランと@OlafDietscheソリューション(バージョンの1つ)は以下のとおりです。

クエリプラン

データ設定スクリプト

CREATE TABLE dbo.Test
(
    id int not null PRIMARY KEY,
    account_num int not null,
    status_code nchar(1)
)
GO

INSERT dbo.Test (id, account_num, status_code)
SELECT 64 ,       1,               'X' UNION ALL
SELECT 82 ,       1,               'Y' UNION ALL
SELECT 72 ,       2,               'Y' UNION ALL
SELECT 87 ,       1,               'Z' UNION ALL
SELECT 91 ,       2,               'X' UNION ALL
SELECT 103,       2,               'Z'
于 2012-11-27T22:54:29.870 に答える
2

副選択を使用したSQLフィドル

select id, account_num, status_code
from mytable
where id in (select min(t1.id)
             from mytable t1
             join mytable t2 on t1.account_num = t2.account_num
                             and t1.id > t2.id
                             and t2.status_code = 'X'
             group by t1.account_num)

およびSQLFiddlewith joinは、どちらもMS SQL Server 2012の場合で、どちらも同じ結果を返します。

select id, account_num, status_code
from mytable
join (select min(t1.id) as min_id
      from mytable t1
      join mytable t2 on t1.account_num = t2.account_num
                      and t1.id > t2.id
                      and t2.status_code = 'X'
      group by t1.account_num) t on id = min_id
于 2012-11-27T22:41:38.627 に答える
0
SELECT MIN(ID), ACCOUNT_NUM, STATUS_CODE FROM (
    SELECT ID,  ACCOUNT_NUM, STATUS_CODE
    FROM ACCOUNT A1
    WHERE EXISTS 
       (SELECT 1 
        FROM ACCOUNT A2 
        WHERE A1.ACCOUNT_NUM = A2.ACCOUNT_NUM
         AND A2.STATUS_CODE = 'X'
         AND A2.ID < A1.ID)
    ) SUB
GROUP BY ACCOUNT_NUM

これがSQLFIDDLEです

于 2012-11-27T22:51:38.230 に答える
0

PostgreSQLでチェックされたデータを含むクエリは次のとおりです。

SELECT t0.*
FROM so13594339 t0 JOIN
 (SELECT min(t1.id), t1.account_num
   FROM so13594339 t1, so13594339 t2
   WHERE t1.account_num = t2.account_num AND t1.id > t2.id AND t2.status_code = 'X'
   GROUP BY t1.account_num
 ) z
 ON t0.id = z.min AND t0.account_num = z.account_num;
于 2012-11-27T22:52:10.200 に答える