3

Diagnose_Date に最も近い運動日を抽出したい 2 つのテーブル Diagnose & Exercise があります。

where条件でDATEDIFF関数を使用して左結合を試みました

SELECT D.ID,D.Diagnose_Date,D.Type1,D.Type2,E.Exercise_Date],E.Field1,E.Field2,E.Field3
FROM Diagnose D
LEFT JOIN Exercise E
ON D.ID=E.ID
WHERE DATEDIFF(DAY,[Diagnose_Date],[Exercise_Date]) BETWEEN -30 AND 30

どんな助けもとても役に立ちます

前もって感謝します


診断表

------------------------------------------
ID     Dignose_Date     Type1    SubType1    
------------------------------------------
1      10/01/2010       01       1.1
2      20/02/2012       02       2.2
3      30/03/2013       01       1.2
------------------------------------------

エクササイズテーブル

------------------------------------------
ID     Exercise_Date  Field1  Field2  Field3
------------------------------------------
1      01/01/2010        x       y      z
2      10/02/2012        a       b      c
2      01/04/2012        e       f      f
3      01/03/2013        x       y      z
3      05/04/2013        a       b      c
3      01/06/2013        x       y      z
------------------------------------------

期待される結果は次のとおりです。

------------------------------------------------------------------------
ID  Diagnose_Date  Exercise_Date Type1 SubType2  Field1  Field2  Field3
------------------------------------------------------------------------
1   10/01/2010     01/01/2010     01    1.1         x       y        z
2   20/02/2012     10/02/2012     02    2.2         a       b        c
3   30/03/2013     05/04/2013     01    1.2         a       b        c
-------------------------------------------------------------------------
4

4 に答える 4

2

まず、CTE で、各診断について、診断日とその診断に関連付けられたすべての運動日の間の最小の時間間隔を取得します。

WITH MIN_DATES_CTE(ID, DATE_DIFF)
AS (
    SELECT ID, MIN(ABS(DATEDIFF(DAY,[Diagnose_Date],[Exercise_Date])))
    FROM Exercise E
    INNER JOIN Diagnose D ON D.ID = E.ID
    GROUP BY E.ID
)

次に、IDと最小の時間間隔でDiagnoseとExerciseに参加します

SELECT D.ID,D.Diagnose_Date,D.Type1,D.Type2,E.Exercise_Date],E.Field1,E.Field2,E.Field3
FROM Diagnose D
LEFT JOIN Exercise E ON D.ID = E.ID
INNER JOIN MIN_DATES_CTE ON MIN_DATES_CTE.ID = E.ID
WHERE ABS(DATEDIFF(DAY,[Diagnose_Date],[Exercise_Date])) = MIN_DATES_CTE.DATE_DIFF
于 2013-11-07T14:02:35.737 に答える
1

OUTER APPLYを使用できます

SELECT  d.ID, 
        d.Diagnose_Date, 
        d.Type1, 
        d.SubType1, 
        e.Exercise_Date, 
        e.Field1, 
        e.Field2, 
        e.Field3
FROM    Diagnose d
        OUTER APPLY
        (   SELECT  TOP 1 Exercise_Date, Field1, Field2, Field3
            FROM    Exercise e
            WHERE   d.ID = e.ID
            AND     DATEDIFF(DAY, d.[Diagnose_Date], e.[Exercise_Date]) BETWEEN -30 AND 30
            ORDER BY ABS(DATEDIFF(DAY, d.[Diagnose_Date], e.[Exercise_Date])) 
        ) e;

SQL Fiddle の例

これについてさらにテストを行ったところ、使用する方法ROW_NUMBER()が最も効率的であることがわかりました。

WITH CTE AS
(   SELECT  d.ID,
            d.Diagnose_Date,
            d.Type1,
            d.SubType1, 
            e.Exercise_Date,
            e.Field1,
            e.Field2,
            e.Field3,
            RowNumber = ROW_NUMBER() OVER (PARTITION BY d.ID ORDER BY ABS(DATEDIFF(DAY,[Diagnose_Date],[Exercise_Date])))
    FROM    Diagnose D
            LEFT JOIN Exercise E 
                ON D.ID = E.ID
)
SELECT  ID,
        Diagnose_Date,
        Type1,
        SubType1, 
        EID = ID,
        Exercise_Date,
        Field1,
        Field2,
        Field3
FROM    CTE
WHERE   RowNumber = 1;

これを最初のソリューションと比較し、比較のために最も賛成票が多かった回答を比較しました。結果は次のとおりです。

外部適用

Cost relative to batch: 34%
--------------------------------------------------
Table 'Exercise'. Scan count 3, logical reads 3
Table 'Diagnose'. Scan count 1, logical reads 1
--------------------------------------------------
Total. Scan count 4, logical reads 4

AGGREGATES を使用した自己結合 (これまでの最高投票数)

Cost relative to batch: 51%
--------------------------------------------------
Table 'Worktable'. Scan count 0, logical reads 0
Table 'Exercise'. Scan count 2, logical reads 4
Table 'Diagnose'. Scan count 2, logical reads 2
--------------------------------------------------
Total. Scan count 4, logical reads 6

ROW_NUMBER()

Cost relative to batch: 15%
--------------------------------------------------
Table 'Exercise'. Scan count 1, logical reads 3
Table 'Diagnose'. Scan count 1, logical reads 1
--------------------------------------------------
Total. Scan count 2, logical reads 4

SQL Fiddle の例

そのため、ROW_NUMBERソリューションの IO 統計が最も低く、推定コストも最も低くなります。

于 2013-11-07T13:55:01.250 に答える
1

互いに最も近い日付に基づいて、単一の診断エントリを単一の運動エントリと照合しているだけだと思います。

これが私の考え方です。診断と演習を
完全JOINに実行し、絶対的な日付の違いで昇順で並べます。

SELECT
    D.ID,
    D.Date,
    E.ID,
    E.Date,
    ABS(DATEDIFF(day, D.Date, E.Date)) Diff

FROM Diagnosis D, Exercise E
ORDER BY Diff

次のような結果が得られます。

ID  Date        ID  Date        Diff
3   2013-03-30  5   2013-03-25  5
2   2012-02-20  2   2012-02-10  10
3   2013-03-30  4   2013-03-01  29
2   2012-02-20  3   2012-04-01  41
3   2013-03-30  6   2013-06-01  63
1   2010-10-01  1   2010-01-01  273
3   2013-03-30  3   2012-04-01  363
2   2012-02-20  4   2013-03-01  375
2   2012-02-20  5   2013-03-25  399
3   2013-03-30  2   2012-02-10  414
2   2012-02-20  6   2013-06-01  467
1   2010-10-01  2   2012-02-10  497
1   2010-10-01  3   2012-04-01  548
2   2012-02-20  1   2010-01-01  780
1   2010-10-01  4   2013-03-01  882
1   2010-10-01  5   2013-03-25  906
1   2010-10-01  6   2013-06-01  974
3   2013-03-30  1   2010-01-01  1184

これで、互いに最も近い日付と、それらが離れている日数を確認できます。

もちろん、これは使用しませんが、このリストから最初のものを選択できます。

SELECT TOP 1
    D.ID,
    D.Date,
    E.ID,
    E.Date,
    ABS(DATEDIFF(day, D.Date, E.Date)) Diff

FROM Diagnosis D, Exercise E
ORDER BY Diff

このステートメントをLEFT結合に組み込むことができるようになったため、別の日付と一致する日付を個別に選択できます。
このような:

SELECT
    fD.ID,
    fD.Date,
    fE.ID,
    fE.Date
FROM
    Diagnosis fD
    LEFT JOIN Exercise fE
        ON fE.ID = (SELECT TOP 1 E.ID
                        FROM Diagnosis D, Exercise E
                        WHERE D.ID = fD.ID
                        ORDER BY ABS(DATEDIFF(day, D.Date, E.Date)))

結果は次のとおりです。

ID  Date        ID  Date
1   2010-10-01  1   2010-01-01
2   2012-02-20  2   2012-02-10
3   2013-03-30  5   2013-03-25
于 2013-11-07T13:53:55.540 に答える
0

標準 SQL のみを使用:

SELECT D.ID, D.Diagnose_Date, D.Type1, D.SubType1, E.Exercise_Date, E.Field1, E.Field2, E.Field3
FROM Diagnose D
LEFT JOIN Exercise E
ON E.ID=D.ID AND
   E.Exercise_Date=(SELECT MAX(Exercise_Date) FROM Exercise WHERE Exercise.ID=D.ID AND Exercise.Exercise_Date<=D.Diagnose_Date)
于 2013-11-07T14:03:42.500 に答える