SQL, INSERT в стиле foreach-loop, основанный на вставленном значении, которое нужно выбрать повторно, возможно? - PullRequest
3 голосов
/ 09 марта 2019

Текущее состояние

У меня есть 4 таблицы, которые выглядят следующим образом Example table При следующих условиях

  • DataMessages.SenderID - это FK с DataUser.UserIDв качестве ссылки
  • Data_UserGroup.UserID - это FK с DataUser.UserID в качестве ссылки
  • DataMessageRecipient.RecipID - это FK с DataUser.UserID в качестве ссылки
  • DataMessageRecipient.DestID - это FKс DataUser.DestID в качестве ссылки
  • DataMessageRecipient.MssgID - это FK с DataMessages.ID в качестве ссылки
  • DataMessages.ID и DataMessageRecipient.EntryID являются IDENTITY() столбец

И этот AFTER INSERT триггер на таблице dbo.DataMessages

CREATE TRIGGER OnNewQueue ON dbo.DataMessages AFTER INSERT AS 
BEGIN
    SET NOCOUNT ON;
    DECLARE @inTabs Table
    (ID INT);
    /*Part that fetch the IDENTITY() column*/
    INSERT INTO @inTabs SELECT DataMessages.ID FROM DataMessages
        INNER JOIN inserted INS ON
            INS.SenderID = DataMessages.SenderID AND
            INS.MssgID = DataMessages.MssgID AND
            INS.CreatedAt = DataMessages.CreatedAt;
    /*
        DataMessages.CreatedAt (DateTime2), DataMessages.MssgID (int) are
        ommited from the picture, but those columns AND-ed will guaranteed to
        return unique rows because a SenderID cannot have duplicate MssgID
        even more on same CreatedAt time
    */
    INSERT INTO dbo.DataMessageRecipient (MssgID, RecipID, DestID)
        SELECT 
            inTbl.ID,
            DataUser.UserID,
            DataUser.DestID 
        FROM
            @inTabs AS inTbl,
            DataUser
        WHERE
            DataUser.UserID IN
            (
                SELECT Data_UserGroup.UserID 
                FROM Data_UserGroup
                WHERE Data_UserGroup.GroupID IN
                (
                    SELECT Data_UserGroup.GroupID 
                    FROM Data_UserGroup, inserted inr
                    WHERE Data_UserGroup.UserID = inr.SenderID
                )
            );
END

Чего я пытаюсь достичь

Чего я пытаюсь достичь, так это вставить DataMessages, будь то вставка из одной строки или из нескольких строк, вставьте DataMessageRecipient (s) со следующими условиями:

  1. RecipID и DestID из таблицы DataUser, гдеDataMessages.SenderID разделяют те же Data_UserGroup.GroupID (s)
  2. MssgID из вставленного DataMessages.ID, с RecipID, связанного со вставленным SenderID на основе условия № 1
  3. (необязательно для SQL) вставкаПолучатели ted не могут включать свой собственный SenderID в качестве RecipID

Проблема

INSERT INTO dbo.DataMessages (SenderID) 
    (10)

INSERT INTO dbo.DataMessages (SenderID) 
    (-83)

INSERT INTO dbo.DataMessages (SenderID) 
    (2213)

Вышеуказанные команды / запросы ведут себя и приводят в соответствии с ожиданиями, так как каждая из нихЭто разные отдельные запросы (удовлетворяющие требованиям, с условием исключения № 3), проблема возникает при попытке многострочного INSERT (например, вот так)

INSERT INTO dbo.DataMessages (SenderID) 
    (10), (83), (2213)

Ожидаемый результат, независимо от одного илимногострочная вставка, foreach вставленная DataMessages, каждая вставленная будет иметь «свои» DataMessageRecipient записи с RecipID, связанными с каждой вставленной SenderID на основе записей в Data_UserGroup, где RecipID и SenderID разделяютто же самое GroupID (s)

То, что в настоящее время приводит к многострочному INSERT, при каждом вставленном DataMessages 'Получатель' объединяется, таким образом, все новые вставленные DataMessage будут иметь общих Получателей

Пример

рассмотрите следующие данные:

|     DataUser    |   |    Data_UserGroup  |   |   DataMessages  |
|:------:|:------:|:-:|:------:|:---------:|:-:|:----:|:--------:|
| UserID | DestID |   | UserID |  GroupID  |   |  ID  | SenderID |
|    1   |   -1   |   |    4   |     10    |   |  100 |     4    |
|    2   |   -2   |   |    5   |     10    |   |  101 |     1    |
|    3   |   -3   |   |    2   |     11    |   |  102 |     5    |
|    4   |   -4   |   |    1   |     12    |   |      |          |
|    5   |   -5   |   |    1   |     13    |   |      |          |
|    6   |   -6   |   |    3   |     13    |   |      |          |
|        |        |   |    5   |     13    |   |      |          |
|        |        |   |    6   |     13    |   |      |          |

независимо от '1089 *' 'путей' ', это должно было бы привести к этому DataMessageRecipient

| EntryID | MssgID | RecipID | DestID |
|:-------:|:------:|:-------:|:------:|
|         |   100  |    4    |   -4   |
|         |   100  |    5    |   -5   |
|         |   101  |    1    |   -1   |
|         |   101  |    3    |   -3   |
|         |   101  |    5    |   -5   |
|         |   102  |    5    |   -5   |
|         |   102  |    4    |   -4   |
|         |   102  |    1    |   -1   |
|         |   102  |    3    |   -3   |

/*
 Note The RecipID is STILL included as the recipients.
 This is 'okay' for now, as the logic 
 outside SQL can filter this out
*/

но вместо этого, если DataMessage вставляется с несколькими строками INSERT, результат будет таким:

| EntryID | MssgID | RecipID | DestID |
|:-------:|:------:|:-------:|:------:|
|         |   101  |    1    |   -1   |
|         |   101  |    3    |   -3   |
|         |   101  |    4    |   -4   |
|         |   101  |    5    |   -5   |
|         |   102  |    1    |   -1   |
|         |   102  |    3    |   -3   |
|         |   102  |    4    |   -4   |
|         |   102  |    5    |   -5   |
|         |   103  |    1    |   -1   |
|         |   103  |    3    |   -3   |
|         |   103  |    4    |   -4   |
|         |   103  |    5    |   -5   |

Вопрос (ы)

Как я могудостичь ожидаемого результата?Возможно ли сделать такие вещи внутри логики SQL?или я должен вытащить вставленный результат DataMessages и постобработать его в логике бэкэнда, где я могу сделать для каждого цикла для каждого вставленного идентификатора?

Спасибо

Ответы [ 2 ]

0 голосов
/ 10 марта 2019

Причина, по которой вы получаете такое поведение, заключается в том, что ваш самый внутренний запрос:

SELECT Data_UserGroup.GroupID 
FROM Data_UserGroup, inserted inr
WHERE Data_UserGroup.UserID = inr.SenderID

возвращает ВСЕ GroupID, применимые для вашей вставки.

Таким образом, когда вы делаете одну вставку, она работает, ноКогда вы вставляете несколько, вы получаете группы всех строк, и для каждого DataMessage вы получите столько строк, сколько строк в Data_UserGroup, содержащих ЛЮБОЙ GroupID, который соответствует вашему запросу.

Также: зачем использовать уловкуполучить идентификационную колонку?В таблице INSERTED также есть этот столбец.

Вот мое предложение:

(вставка @inTabs не требуется вообще)

insert into dbo.DataMessageRecipient (MssgID, RecipID, DestID)
    select
        ins.ID as MssgID
        ,g2.UserID as RecipID
        ,u.DestID as DestID
    from
        inserted ins
        inner join Data_UserGroup g on ins.SenderID=g.UserID -- first join to get the groupID
        inner join Data_UserGroup g2 on g2.GroupID=g1.GroupID -- again join to get all userids of this groupid
        inner join DataUser u on g2.UserID=u.UserID -- to get destID

Кроме того, если вы хотите опуститьоригинальный идентификатор пользователя, вы можете добавить в конце:

where ins.SenderID<>g2.UserID

0 голосов
/ 10 марта 2019

триггер может получить доступ к вставленному, извлекая идентификаторы любого вставленного

create trigger theTriggerName 
    on dbo.DataMessages for update
as
insert into dbo.DataMessagesInserted (insertedID)
select ID from inserted
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...