【问题标题】:Insert multiple rows from a single row inside an insert into select query从插入内的单行中插入多行到选择查询中
【发布时间】:2014-05-05 02:18:26
【问题描述】:

我有以下架构(更复杂的版本):

CREATE TABLE Messages (
    ItemId INT IDENTITY PRIMARY KEY,
    Name VARCHAR(20) NOT NULL,
    DeliveryType INT NOT NULL
);

CREATE TABLE NotificationsQueue (
    ItemId INT NOT NULL,
    DeliveryType INT NOT NULL
);

DeliveryType 的可能值为:

0 -> none
1 -> mail
2 -> email
3 -> both

现在,Messages 表中有一些条目:

INSERT INTO Messages(Name, DeliveryType) Values
('Test0', 0),
('Test1', 1),
('Test2', 2),
('Test3', 3)

我需要像这样填充 NotificationsQueue 表:

  • 当 DeliveryType = 0 时,不要插入任何东西
  • 当 DeliveryType = 1 OR DeliveryType = 2 时,插入一个元组:(ItemId, DeliveryType)
  • 当 DeliveryType = 3 时,插入两个元组:(ItemId, 1), (ItemId, 2)

我这样做的尝试导致了以下两个查询:

INSERT INTO NotificationsQueue (ItemId, DeliveryType) SELECT ItemId, 1 AS DeliveryType FROM Messages WHERE DeliveryType IN (1, 3)
INSERT INTO NotificationsQueue (ItemId, DeliveryType) SELECT ItemId, 2 AS DeliveryType FROM Messages WHERE DeliveryType IN (2, 3)

尽管这样可行,但插入的选择语句在实践中要复杂得多,所以我想知道是否有任何好的方法可以将它们合并到一个查询中,以避免重复。

PS:我不允许在Messages 表中更改架构或添加重复项。

【问题讨论】:

  • 当然,但我仍然需要从其他表中选择内容,因为Messages 不包含我需要放入NotificationsQueue 的所有信息。即使在触发器内部,我如何才能使用单个 INSERT 语句?
  • 那么,你能不能在变量中收集信息,然后插入值?
  • 嗯,好吧,想想看,如果我使用带有 IF 语句的触发器,那可能还不错。感谢您的提示! :)

标签: sql sql-server select insert bulkinsert


【解决方案1】:

如果你可以使用触发器,你可以这样做

CREATE TRIGGER dbo.Messages_Inserted ON dbo.[Messages]
    FOR INSERT
AS
    INSERT INTO dbo.[NotificationsQueue]
            ( ItemId
            ,DeliveryType
            )
            SELECT ItemId
                   ,1
                FROM INSERTED
                WHERE DeliveryType IN ( 1, 3 )
            UNION ALL
            SELECT ItemId
                   ,2
                FROM INSERTED
                WHERE DeliveryType IN ( 2, 3 )
GO

INSERT INTO dbo.[Messages](Name, DeliveryType) Values
('Test0', 0),
('Test1', 1),
('Test2', 2),
('Test3', 3)

SELECT * FROM dbo.[Messages]
SELECT * FROM dbo.NotificationsQueue

【讨论】:

  • 是的,这听起来可行。 @PeterRing 的评论给了我一个类似的想法,我现在就尝试一下。
  • 这也将适应您一次向表中插入超过 1 个的时间。使用变量时,您需要考虑将插入超过 1 行,但变量仅保存分配给它的最后一个值。
  • 好的,很公平 :) 再次感谢!
  • 我接受这个触发想法的答案,但我最终将它与来自other answer 的@EricZ 的创意 CTE 查询相结合。
【解决方案2】:

如果你只想要一个选择中的所有内容,我会创建一个查找表来翻译类型,就像这样

;WITH cte AS (SELECT * FROM (VALUES (1,1),(2,2),(3,1),(3,2)) a(DeliveryType,type)) 
SELECT ItemId, t.type AS DeliveryType 
FROM Messages m
INNER JOIN    cte t
    ON t.DeliveryType = m.DeliveryType 

【讨论】:

  • 有志者事竟成!感谢您提供创造性的解决方案,但我认为在我的情况下触发器会更干净。
  • 其实这非常有用,即使我在使用触发器。再次感谢! :)
【解决方案3】:

可能是这样的:

INSERT INTO NotificationsQueue (ItemId, DeliveryType) 
select itemid, case when deliverytype = 3 then n else deliverytype end
from messages
inner join (values(1), (2)) x(n) on n <= case when deliverytype=1 then 2 else deliverytype end -1

【讨论】:

  • @EricZ 提出的 CTE 查找表看起来更好,但谢谢。
猜你喜欢
  • 1970-01-01
  • 2013-10-31
  • 2018-05-16
  • 1970-01-01
  • 2016-08-26
  • 2019-07-05
  • 2013-11-15
  • 1970-01-01
相关资源
最近更新 更多