Получите ROWCOUNT за все действия, выполненные в MERGE Statement - PullRequest
0 голосов
/ 30 января 2019

Я был поражен этим заявлением MERGE, что компания на самом деле не делает Замедление, изменяющее измерение типа 2 , но закрывается.Как ни странно, это даже не аналитические данные, но давайте проигнорируем это ужасное решение.У меня есть эта рабочая ссылка HashBytes на указанные измененные строки.К сожалению, для решения всех сценариев я получил дополнительный INSERT в конце из временной таблицы, которая фактически содержит обновленные строки.

Увы, это функционально, но если у вас есть более эффективный дизайн, пожалуйста, поделитесь.Буду премного благодарен.

Однако я пытаюсь получить row count, представляющий не только INSERT из таблицы Temp, но и обновления И новый INSERTS, все это отдельные отдельные действия со своими собственнымиrow count, что мне нужно документировать и учитывать.

Как я могу это сделать, пожалуйста?

DECLARE @dtNow AS DATETIME = GetDate()
DECLARE @dtPast AS DATETIME = DATEADD(day,-1,GetDate())
DECLARE @dtFuture AS DATETIME = '22991231'
    SET NOCOUNT ON;

  -- Temp Table is JUST Updating Rows reflecting 
--Historical Marker on existing row No content change to row's columnar     content data 

IF OBJECT_ID('tempdb..#TheTempTableName') IS NOT NULL DROP TABLE     #TheTempTableName


CREATE TABLE #TheTempTableName 
(
    ABunchOfColumns
    RowCreatedDate datetime NULL,
    RowEffectiveDate datetime NULL,
    RowTerminationDate datetime NULL,
    RowIsCurrent bit NULL,
    RowHash varchar(max) NULL,
)

INSERT INTO #TheTempTableName
(
            ABunchOfColumns
                ,RowCreatedDate
                ,RowEffectiveDate
                ,RowTerminationDate
                ,RowIsCurrent
                ,RowHash 
)


SELECT
                ABunchOfColumns
                ,RowCreatedDate
                ,RowEffectiveDate
                ,RowTerminationDate
                ,RowIsCurrent
                ,RowHash 
FROM
    (
        MERGE tblDim WITH (HOLDLOCK) AS target
            USING 
            (
                SELECT          
                ABunchOfColumns
                ,RowCreatedDate
                ,RowEffectiveDate
                ,RowTerminationDate
                ,RowIsCurrent
                ,RowHash 

                FROM dbo.tblStaging
            )       
        AS source
        ON target.PKID  = source.PKID       
        WHEN MATCHED
            AND target.RowIsCurrent = 1
            AND target.RowHash != source.RowHash                    
------- PROCESS ONE -- UPDATE --- HISTORICALLY MARK EXISTING ROWS
            THEN UPDATE SET                     
                    RowEffectiveDate    =   @dtPast
                    ,RowTerminationDate =   @dtPast
                    ,RowIsCurrent   =   0                   
-----  PROCESS TWO -- INSERT ---INSERT NEW ROWS
            WHEN NOT     MATCHED                                                          
            THEN INSERT    ---   THIS INSERT Goes directly into Target ( DIM     ) Table (New Rows not matched with PK = PK ) 
                (
                ABunchOfColumns
                ,RowCreatedDate
                ,RowEffectiveDate
                ,RowTerminationDate
                ,RowIsCurrent
                ,RowHash 
                )
                VALUES
                (                   
                source.ABunchOfColumns
                    ,@dtNow                 --source.RowCreatedDate,
                    ,@dtFuture              ---source.RowEffectiveDate,
                    ,@dtFuture              ---source.RowTerminationDate,
                    ,1                      ---source.RowIsCurrent,
                    ,source.RowHash
                )
-------PROCESS THREE a  -- INSERT ---OUTPUT MATCHED ROWS FROM PROCESS ONE THAT CAUSED     HISTORICAL MARK (CHANGES) "INSERT"
        OUTPUT 
        $action Action_Out,

                ABunchOfColumns
                ,RowCreatedDate
                ,RowEffectiveDate
                ,RowTerminationDate
                ,RowIsCurrent
                ,RowHash 
    )       
    AS MERGE_OUT
WHERE MERGE_OUT.Action_Out = 'UPDATE';

----------PROCESS THREE b  -- INSERT FROM Temp Tbl to final
--Now we flush the data in the temp table into dim table

INSERT INTO tblDim
    (
                ABunchOfColumns
                ,RowCreatedDate
                ,RowEffectiveDate
                ,RowTerminationDate
                ,RowIsCurrent
                ,RowHash 
    )
SELECT
         ABunchOfColumns
        ,@dtNow AS RowCreatedDate
        ,@dtFuture AS RowEffectiveDate
        ,@dtFuture AS RowTerminationDate
        ,1 AS RowIsCurrent
        ,RowHash

FROM #TheTempTableName  
END

Ответы [ 2 ]

0 голосов
/ 31 января 2019

Основываясь на ваших дальнейших комментариях, я думаю, что основная проблема заключается в том, как вы обрабатываете обновления типа 2.Быстрый ответ - вам нужны две операции UPDATE (вставка / обновление);и DELETES на самом деле не DELETES, а ОБНОВЛЕНИЯ на временной метке.

Я сформулировал пример запроса ниже, как обрабатывать обновления типа 2, и результаты должны быть самоочевидными.Я попытался выполнить двойную операцию слияния UPDATE, и интересно, что он не может этого сделать и выдает ошибку: "Действие типа INSERT не разрешено в предложении WHEN MATCHEDОператор MERGE. " Так что я думаю, что нет другого выбора, кроме как разделить обновление и вставку оператора UPDATE.

Последнее соображение также касается DELETE, который проявляется как обновление.Я также обработал это в приведенном ниже коде, как определить, когда действие UPDATE действительно является DELETE.

DROP TABLE IF EXISTS _a
CREATE TABLE _a (
    id int
,val int
,fromdate datetime
,todate datetime
,isactive bit
)

INSERT INTO _a
select 1,100,'2015-Jan-1',NULL,1
UNION ALL select 2,200,'2015-Feb-1',NULL,1
UNION ALL select 3,300,'2015-Mar-1',NULL,1

DROP TABLE IF EXISTS #data
DROP TABLE IF EXISTS #outputdata

select * INTO #data from _a
select TOP 0 action=CAST('' as varchar(10)),* INTO #outputdata from _a

DELETE #data where id = 3
UPDATE #data set val = 2000 where id = 2
INSERT INTO #data
select 4,400,GETDATE(),NULL,1

--select * from #data

-- _a is your data warehouse table using type2

BEGIN TRAN

select Note='OLD STATE OF _a',* from _a

select Note='NEW SET OF DATA',* from #data


MERGE dbo._a T
USING (
    select id,val from #data
) S
ON (S.id = T.id)
WHEN MATCHED
AND ((S.val <> T.val OR (S.val IS NOT NULL AND T.val IS NULL) OR (S.val IS NULL AND T.val IS NOT NULL)))
THEN UPDATE SET  
        todate   = GETDATE()
    ,isactive = 0
WHEN NOT MATCHED BY TARGET
THEN INSERT (id,val,fromdate,todate,isactive)
        VALUES (id,val,GETDATE(),NULL,1)
WHEN NOT MATCHED BY SOURCE --AND T.id IN (SELECT id FROM #data)
--THEN DELETE TYPE2
THEN UPDATE SET  /*NO-PK*/ 
        todate   = GETDATE()
    ,isactive = 0
OUTPUT $action as Action
    ,ISNULL(inserted.id,deleted.id)  as id
    ,ISNULL(inserted.val,deleted.val)  as val
    ,ISNULL(inserted.fromdate,deleted.fromdate)  as fromdate
    ,ISNULL(inserted.todate,deleted.todate)  as todate
    ,ISNULL(inserted.isactive,deleted.isactive)  as isactive
INTO #outputdata;

select Note='Logs Output',* from #outputdata

-- FIND THE NEW RECORD
INSERT INTO _a (id,val,fromdate,todate,isactive)
SELECT a.id,a.val,GETDATE()+.000001,a.todate,a.isactive
FROM #data a
INNER JOIN #outputdata b
on a.id = b.id
WHERE b.action ='UPDATE'

select Note='NEW STATE OF _a',* from _a

SELECT Note='Real Action',d1.id,action=CASE WHEN action='UPDATE' AND d2.id is null then 'DELETE' ELSE action END
FROM #outputdata d1
LEFT JOIN _a d2
on d1.action ='UPDATE' and d1.id = d2.id and d2.isactive =1

ROLLBACK TRAN

Результатами будут:

+-----------------+----+-----+-------------------------+--------+----------+
|      Note       | id | val |        fromdate         | todate | isactive |
+-----------------+----+-----+-------------------------+--------+----------+
| OLD STATE OF _a |  1 | 100 | 2015-01-01 00:00:00.000 | NULL   |        1 |
| OLD STATE OF _a |  2 | 200 | 2015-02-01 00:00:00.000 | NULL   |        1 |
| OLD STATE OF _a |  3 | 300 | 2015-03-01 00:00:00.000 | NULL   |        1 |
+-----------------+----+-----+-------------------------+--------+----------+

+-----------------+----+------+-------------------------+--------+----------+
|      Note       | id | val  |        fromdate         | todate | isactive |
+-----------------+----+------+-------------------------+--------+----------+
| NEW SET OF DATA |  1 |  100 | 2015-01-01 00:00:00.000 | NULL   |        1 |
| NEW SET OF DATA |  2 | 2000 | 2015-02-01 00:00:00.000 | NULL   |        1 |
| NEW SET OF DATA |  4 |  400 | 2019-01-31 09:49:45.943 | NULL   |        1 |
+-----------------+----+------+-------------------------+--------+----------+

+-------------+--------+----+-----+-------------------------+-------------------------+----------+
|    Note     | action | id | val |        fromdate         |         todate          | isactive |
+-------------+--------+----+-----+-------------------------+-------------------------+----------+
| Logs Output | INSERT |  4 | 400 | 2019-01-31 09:51:13.647 | NULL                    |        1 |
| Logs Output | UPDATE |  2 | 200 | 2015-02-01 00:00:00.000 | 2019-01-31 09:51:13.647 |        0 |
| Logs Output | UPDATE |  3 | 300 | 2015-03-01 00:00:00.000 | 2019-01-31 09:51:13.647 |        0 |
+-------------+--------+----+-----+-------------------------+-------------------------+----------+

-- OPERATIONS 1 INSERT 1 UPDATE 1 DELETE
DELETE #data where id = 3
UPDATE #data set val = 2000 where id = 2
INSERT INTO #data
select 4,400,GETDATE(),NULL,1

+-----------------+----+------+-------------------------+-------------------------+----------+
|      Note       | id | val  |        fromdate         |         todate          | isactive |
+-----------------+----+------+-------------------------+-------------------------+----------+
| NEW STATE OF _a |  1 |  100 | 2015-01-01 00:00:00.000 | NULL                    |        1 |
| NEW STATE OF _a |  2 |  200 | 2015-02-01 00:00:00.000 | 2019-01-31 09:51:13.647 |        0 |
| NEW STATE OF _a |  3 |  300 | 2015-03-01 00:00:00.000 | 2019-01-31 09:51:13.647 |        0 |
| NEW STATE OF _a |  4 |  400 | 2019-01-31 09:51:13.647 | NULL                    |        1 |
| NEW STATE OF _a |  2 | 2000 | 2019-01-31 09:51:13.733 | NULL                    |        1 |
+-----------------+----+------+-------------------------+-------------------------+----------+

+-------------+----+--------+
|    Note     | id | action |
+-------------+----+--------+
| Real Action |  4 | INSERT |
| Real Action |  2 | UPDATE |
| Real Action |  3 | DELETE |
+-------------+----+--------+
0 голосов
/ 30 января 2019

Существует два типа удалений (1) реальные удаления (2) обновления первичного ключа.Таким образом, вы также можете сказать, что есть два типа вставок (1) реальные вставки (2) обновления первичного ключа. Обновления всегда являются обновлениями.

Тогда возникает дилемма, когда комбинация вставки / удаления действительно является обновлением.

Обычно, если вы действительно не заботитесь о том, что выше, достаточно простого слияния, подобного этому

MERGE esqlProductTarget T
USING esqlProductSource S
ON (S.ProductID = T.ProductID)
WHEN MATCHED
THEN UPDATE
     SET    T.Name = S.Name,
            T.ProductNumber = S.ProductNumber,
            T.Color = S.Color
WHEN NOT MATCHED BY TARGET
THEN INSERT (ProductID, Name, ProductNumber, Color)
     VALUES (S.ProductID, S.Name, S.ProductNumber, S.Color)
WHEN NOT MATCHED BY SOURCE
THEN DELETE
OUTPUT S.ProductID, $action into @MergeLog;

SELECT MergeAction, Cnt=count(*)
FROM   @MergeLog
GROUP BY MergeAction

Вывод будет выглядеть так:

+-------------+-----+--+
| MergeAction | Cnt |  |
+-------------+-----+--+
| DELETE      | 100 |  |
| UPDATE      |  60 |  |
| INSERT      |  70 |  |
+-------------+-----+--+

См. https://www.essentialsql.com/introduction-merge-statement/

Я не уверен, почему у вас "WHERE MERGE_OUT.Action_Out = 'UPDATE'. Но если вы удалите это, вы сможете получить количество строк. Если вы не поняли ваш запрос.

...