SQL Merge только вставка строк, а не обновление - PullRequest
0 голосов
/ 25 апреля 2019

В SQL Server 2016 я пытаюсь создать / обновить записи в моей целевой таблице с помощью Merge, но я думаю, что сталкиваюсь с ограничением, когда Merge делает только один проход через данные, поэтому я получаю все вставки и нет обновлений.

В целевой таблице (которая в начале слияния пуста) должна быть только одна запись в день / sitename / username, но она создает несколько записей в день. То, что я хотел бы сделать, это:

"Итерация по каждой строке исходной таблицы; если в целевой таблице нет строки для этого дня / sitename / username, вставьте новую запись; если в целевой таблице не существует строки для этого дня / sitename / username обновите его, добавив в BytesTransferred и увеличивая Соединения (но если в исходной таблице несколько идентичных идентификаторов транзакции, то для этого идентификатора транзакции можно увеличивать количество соединений только один раз). "

Вот созданная целевая таблица:

CREATE TABLE tbl_Report_Active_Users(
    ID [int] IDENTITY(1,1) NOT NULL,
    DayOfRecord [date] NULL,
    SiteName [nvarchar](50) NULL,
    UserName [nvarchar](50) NULL,
    Connections [bigint] NULL,
    BytesTransferred [numeric](18, 0) NULL,
CONSTRAINT [PK_tbl_Report_User_Activity] PRIMARY KEY CLUSTERED 
)
CREATE NONCLUSTERED INDEX IX_tbl_Report_Active_Users_dayofrecord_sitename_username ON
 tbl_Report_Active_Users (DayOfRecord,SiteName,UserName)

и вот код слияния, который я пытаюсь:

MERGE INTO tbl_Report_Active_Users AS target
USING (SELECT p.ProtocolCommandID, p.TransactionID, p.BytesTransferred,
 CONVERT(date,p.Time_stamp) As DayOfRecord, p.SiteName, p.UserName
        FROM tbl_ProtocolCommands p) AS source
    (ProtocolCommandID, TransactionID, BytesTransferred, DayOfRecord, SiteName,
UserName)
ON (target.DayOfRecord = source.DayOfRecord AND target.SiteName = source.SiteName 
AND target.UserName = source.UserName)
WHEN MATCHED THEN
    UPDATE SET BytesTransferred = target.BytesTransferred + source.BytesTransferred,
        Connections = target.Connections + 
                CASE WHEN source.ProtocolCommandID = (SELECT MIN(p.ProtocolCommandID)
                FROM tbl_ProtocolCommands p 
                INNER JOIN tbl_Authentications a ON a.TransactionID = p.TransactionID
                WHERE p.TransactionID = source.TransactionID AND a.ResultID=0
                GROUP BY p.TransactionID
                ) THEN 1 ELSE 0 END
WHEN NOT MATCHED THEN
    INSERT (DayOfRecord,SiteName,UserName,Connections,BytesTransferred)
    VALUES (source.DayOfRecord,source.SiteName,source.UserName,1,
source.BytesTransferred);

В целевой таблице я получаю такие записи:

ID  DayOfRecord SiteName    UserName    Connections BytesTransferred    (TransactionID)
1   2018-06-27  sales1  Jenkins 1   1829    333
2   2018-06-27  sales1  Jenkins 1   1829    333
3   2018-06-27  sales1  Jenkins 1   500     333
4   2018-06-27  sales1  Smith   1   500     376
5   2018-06-27  sales1  Smith   1   20559   391

Но вместо этого можно ожидать:

1   2018-06-27  sales1  Jenkins 1   4158
2   2018-06-27  sales1  Smith   2   21059

Есть мысли о том, как лучше всего это сделать?

1 Ответ

0 голосов
/ 25 апреля 2019

Я думаю, что вы столкнулись с этой проблемой из-за соединения с таблицей "tbl_authentications". Остальная часть вашего слияния работает нормально,

    MERGE INTO tbl_report_active_users AS target 
using (SELECT p.protocolcommandid, 
              p.transactionid, 
              p.bytestransferred, 
              CONVERT(DATE, p.time_stamp) AS DayOfRecord, 
              p.sitename, 
              p.username 
       FROM   tbl_protocolcommands p) AS source
        (protocolcommandid, 
       transactionid, bytestransferred, dayofrecord, sitename, username) 

ON ( target.dayofrecord = source.dayofrecord 
     AND target.sitename = source.sitename 
     AND target.username = source.username ) 
WHEN matched THEN 
  UPDATE SET bytestransferred = target.bytestransferred 
                                + source.bytestransferred, 
             connections = target.connections + CASE WHEN 
                           source.protocolcommandid = (SELECT 
                           Min(p.protocolcommandid) FROM tbl_protocolcommands p 
                           --INNER JOIN 
                           --tbl_authentications a 
                           --ON a.transactionid = p.transactionid 
                            WHERE 
                           p.transactionid = 
                           source.transactionid 
                           --AND a.resultid=0
                            GROUP BY 
                           p.transactionid ) 
                           THEN 1 ELSE 0 END 
WHEN NOT matched THEN 
  INSERT (dayofrecord, 
          sitename, 
          username, 
          connections, 
          bytestransferred) 
  VALUES (source.dayofrecord, 
          source.sitename, 
          source.username, 
          1, 
          source.bytestransferred); 
...