Альтернатива курсору SQL - PullRequest
0 голосов
/ 30 ноября 2018

Нужен совет по улучшению / переписыванию запроса ниже.Таким образом, у меня есть таблица, которую я пытаюсь рекурсивно перебрать, чтобы сгенерировать отношения родитель-ребенок.

Например, таблица имеет:

PAT_ID 1

+-------+------------------+------------------+
| EP_ID |    START_DTTM    |     END_DTTM     |
+-------+------------------+------------------+
|     1 | 01/12/2018 10:00 | 02/12/2018 15:00 |
|     2 | 03/12/2018 10:00 | 10/12/2018 15:00 |
|     3 | 04/12/2018 10:00 | 06/12/2018 15:00 |
|     4 | 07/12/2018 10:00 | 09/12/2018 15:00 |
|     5 | 11/12/2018 10:00 | 13/12/2018 15:00 |
|     6 | 12/12/2018 10:00 | 12/12/2018 15:00 |
|     7 | 01/12/2019 10:00 | 02/12/2019 15:00 |
+-------+------------------+------------------+

Желаемый вывод:

+--------+-------+-----------+-----------------------------------------------------------------------------------------+
| PAT_ID | EP_ID | PARENT_ID |                                        LINK_TYPE                                        |
+--------+-------+-----------+-----------------------------------------------------------------------------------------+
|      1 |     1 |         0 | 'Parent'                                                                                |
|      1 |     2 |         1 | 'Child' (Rule for child is that START_DTTM is less than 24 hours of parent EP_ID)       |
|      1 |     3 |         2 | 'Inner' (Rule for inner is that START_DTTM is between START_DTTM and END_DTTM of Child) |
|      1 |     4 |         2 | 'Inner'                                                                                 |
|      1 |     5 |         0 | 'Parent' (doesnt qualify as child or inner for any row)                                 |
|      1 |     6 |         5 | 'Child'                                                                                 |
|      1 |     7 |         0 | 'Parent                                                                                 |
+--------+-------+-----------+-----------------------------------------------------------------------------------------+

~~~ Я попытался написать логику с помощью курсора, который кажетсявозвращать строки нормально, но базовая таблица содержит более 10 м строк, поэтому вряд ли она будет завершена до моего выхода на пенсию, к сожалению, еще 30 лет вперед :).Нужен совет эксперта сообщества о том, как я могу подойти к этому запросу (я пробовал цикл while, который был медленнее, чем курсор).

Заранее спасибо!

IF (OBJECT_ID('tempdb..#PARENT') IS NOT NULL)
BEGIN
    DROP TABLE #PARENT
END

IF (OBJECT_ID('tempdb..#CHILD') IS NOT NULL)
BEGIN
    DROP TABLE #CHILD
END


CREATE TABLE #Parent (
    EP_ID INT
    ,ID VARCHAR(20)
    ,PAT_ID VARCHAR(50)
    ,START_DTTM DATETIME
    ,END_DTTM DATETIME
    ,CT_DESC VARCHAR(100)
    ,CT_CODE VARCHAR(10)
    ,PARENT_EP_ID INT
    ,PARENT_ID VARCHAR(20)
    ,LINK VARCHAR(20)
    ,PROCESSED INT
    ,PARENT_EP_SEQ INT
    )

CREATE TABLE #CHILD (
    EP_ID INT
    ,ID VARCHAR(20)
    ,PAT_ID VARCHAR(50)
    ,START_DTTM DATETIME
    ,END_DTTM DATETIME
    ,CT_DESC VARCHAR(100)
    ,CT_CODE VARCHAR(10)
    ,PARENT_EP_ID INT
    ,PARENT_ID VARCHAR(20)
    ,LINK VARCHAR(20)
    ,PROCESSED INT
    ,CHILD_EP_SEQ INT
    )


INSERT INTO #PARENT
SELECT deip.EP_ID
    ,deip.ID
    ,deip.PAT_ID
    ,START_DTTM
    ,END_DTTM
    ,CT_DESC
    ,CT_CODE
    ,0
    ,''
    ,'Parent' AS LINK
    ,0 AS PROCESSED
    ,row_number() OVER (
        PARTITION BY deip.PAT_ID ORDER BY START_DTTM
        ) AS PARENT_EP_SEQ
FROM dbo.deip
INNER JOIN dbo.dEP ep ON deip.EP_ID = ep.EP_ID
dbo.RE ep.STATUS IN (
        'A'
        ,'D'
        )
    AND ep.RECORD_STATUS = 'A'
    AND
    event_type = 'Active'
    AND CT_CODE <> '10'

PRINT 'Parent Done'

DECLARE @PARENT_EP_SEQ INT
DECLARE @PAT_ID INT
DECLARE @EP_ID INT
DECLARE @COUNT BIGINT

DECLARE ChildCursor CURSOR LOCAL FAST_FORWARD
FOR
SELECT PARENT_EP_SEQ
    ,PAT_ID
    ,EP_ID
FROM #PARENT
where PROCESSED = 0

OPEN ChildCursor

while 1 = 1
BEGIN
    -- And then fetch
    FETCH NEXT
    FROM ChildCursor
    INTO @PARENT_EP_SEQ
        ,@PAT_ID
        ,@EP_ID

    -- And then, if no row is fetched, exit the loop
    IF @@fetch_status <> 0
    BEGIN
        BREAK
    END
    INSERT INTO #CHILD
    SELECT C.EP_ID
        ,C.ID
        ,P.PAT_ID
        ,C.START_DTTM
        ,C.END_DTTM
        ,C.CT_DESC
        ,C.CT_CODE
        ,P.EP_ID AS PARENT_EP_ID
        ,P.ID
        ,'Child' AS LINK
        ,0 AS PROCESSED
        ,row_number() OVER (
            PARTITION BY C.PAT_ID ORDER BY c.START_DTTM
            ) AS CHILD_EP_SEQ
    FROM #PARENT p
    INNER JOIN #PARENT C ON p.PAT_ID = c.PAT_ID
    dbo.RE P.PAT_ID = @PAT_ID
        AND P.EP_ID = @EP_ID
        AND P.PARENT_EP_SEQ = @PARENT_EP_SEQ
        AND P.EP_ID <> C.EP_ID
        AND P.PARENT_EP_SEQ <> C.PARENT_EP_SEQ
        AND datediff(hh, isnull(p.END_DTTM, getdate()), C.START_DTTM) BETWEEN 0
            AND 24
        AND p.PROCESSED = 0
        AND c.CT_CODE <> '10'
    ORDER BY p.PARENT_EP_SEQ

    DELETE P
    FROM #PARENT P
    INNER JOIN #CHILD c ON p.PAT_ID = c.PAT_ID
        AND p.EP_ID = c.EP_ID

    UPDATE #PARENT
    SET Processed = 1
    dbo.RE PAT_ID = @PAT_ID
        AND EP_ID = @EP_ID
        AND PARENT_EP_SEQ = @PARENT_EP_SEQ
END

CLOSE ChildCursor

DEALLOCATE ChildCursor

PRINT 'Child Done'

После размышления: я думал об использовании рекурсивного / иерархического CTE, но у меня нет ключа, который определяет отношения.Родитель-> дочерняя ассоциация - это то, что я пытаюсь создать.

1 Ответ

0 голосов
/ 30 ноября 2018

Вы можете использовать многопоточность своего подхода CURSOR, поскольку это звучит как одноразовый, а не то, что вы будете делать снова и снова.

Редактируйте код CURSOR с помощью фильтра, который будет иметь егопоработать над 500k строк, запустить его, открыть другое окно и добавить фильтр, который будет работать с 500,001-1 млн. строк, запустить его и т. д.

Могу поспорить, что это будет сделано, прежде чем вы придумалиCTE / подход, основанный на множестве для этой логики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...