[英]Insert data twice into the same table using cursor
我有两个表cursor_created
和cursor_copied
具有相同的列。 我想使用cursor_created
获取数据并将其插入cursor_copied
两次。
查询:
DECLARE @ID INT
DECLARE @Name NVARCHAR(50)
DECLARE @Amount DECIMAL(18,0)
DECLARE @Date NVARCHAR(50)
DECLARE IDs CURSOR FOR
SELECT
ID, Name, Amount, Date
FROM
cursor_created
OPEN IDs
FETCH NEXT FROM IDs into @ID, @Name, @Amount, @Date
WHILE @@FETCH_STATUS = 0
BEGIN
INSERT INTO cursor_copied (id, name, amount, date)
VALUES (@ID, @Name, @Amount, @Date)
----Verify that Data in TestTable
--print @ID
--print @Name
--print @Amount
--print @Date
--SELECT @ID, @Name, @Amount, @Date FROM cursor_copied
FETCH NEXT FROM IDs into @ID, @Name, @Amount, @Date
END
CLOSE IDs
DEALLOCATE IDs
输出:
ID Name Amount Date
------------------------------------------
1 A 2000 2008-03-15 18:15:43.000
2 B 3000 2008-03-15 18:15:43.000
3 C 4000 2008-03-15 18:15:43.000
我想要这样:
ID Name Amount Date
------------------------------------------
1 A 2000 2008-03-15 18:15:43.000
2 B 3000 2008-03-15 18:15:43.000
3 C 4000 2008-03-15 18:15:43.000
1 A 2000 2008-03-15 18:15:43.000
2 B 3000 2008-03-15 18:15:43.000
3 C 4000 2008-03-15 18:15:43.000
您应该after insert
触发器after insert
使用。
您可以在cursor_inserted
表on after insert
触发器on after insert
设置on after insert
并控制该表上的插入事件,然后插入重复行。
CREATE TRIGGER DublicateInsert ON cursor_copied
AFTER INSERT
AS
BEGIN
INSERT INTO cursor_copied (id, name, amount, date)
SELECT id, name, amount, date
FROM INSERTED
END
或者您可以使用此语法解决问题
INSERT INTO cursor_copied (id, name, amount, date)
OUTPUT inserted.id, inserted.name,inserted.amount,inserted.date
INTO cursor_copied (id, name, amount, date)
VALUES (@ID, @Name, @Amount, @Date)
为此使用游标是一个错误。 您应该在以下位置使用设置操作:
INSERT INTO cursor_copied (id, name, amount, date)
SELECT ID, Name, Amount, Date
FROM cursor_created CROSS APPLY
(VALUES (1), (2)) copies(n);
即使您正在学习游标,也非常重要的是学习适当的游标。 当代码可以被单个查询替换时,它们几乎是不合适的。
您只需在光标内按如下所示重写您的插入:
INSERT INTO cursor_copied (id, name, amount, date)
VALUES (@ID, @Name, @Amount, @Date),
(@ID, @Name, @Amount, @Date)
但是您选择的解决方案可能不是解决此类问题的好方法。 如果您对其他解决方案感兴趣,请阅读以下故事。
解决方案1
请参阅@GordonLinoff的答案
解决方案2
让我们逐步解决问题:
首先,我想有两个这样的表:
CREATE TABLE t1(Id INT, Name NVARCHAR(50), Amount DECIMAL(18,0), Date NVARCHAR(50))
GO
CREATE TABLE t1_copy(Id INT, Name NVARCHAR(50), Amount DECIMAL(18,0), Date NVARCHAR(50))
然后我想,我已经将以下记录插入到t1
:
INSERT INTO t1 VALUES
(1,'A', 2000,'2008-03-15 18:15:43.000'),
(2,'B', 3000,'2008-03-15 18:15:43.000'),
(3,'C', 4000,'2008-03-15 18:15:43.000')
接下来,我需要考虑一个查询,这可以帮助我生成重复的记录。 我有很多可用的选项,例如提到的@GordonLinoff的Cross Apply
。 另一种方法是按如下方式使用UNION ALL
:
SELECT t1.Id,
t1.Name,
t1.Amount,
t1.Date FROM dbo.t1
UNION ALL
SELECT Id,
Name,
Amount,
Date FROM dbo.t1;
此查询将产生所需的结果,而我在这里需要做的就是将它们简单地插入到目标表中,如下所示:
INSERT INTO dbo.t1_copy(Id,Name,Amount,Date)
SELECT t1.Id,
t1.Name,
t1.Amount,
t1.Date FROM dbo.t1
UNION ALL
SELECT Id,
Name,
Amount,
Date FROM dbo.t1;
很明显,在插入表之前,您可能需要注意Primary Key
或Identity
列(如果存在)!
解决方案3
您可以使用GO
! 像这样:
INSERT INTO dbo.t1_copy(Id,Name,Amount,Date)
SELECT Id,Name,Amount,Date FROM dbo.t1
GO 2
这不是我建议的方式,因为GO是批次分隔符,并且会给您带来麻烦。 同样,前面提到的查询将作为两个单独的事务执行,这又可能是一个麻烦点!
解决方案4
您可以使用OUTPUT
运算符。 但是由于复杂性,我再次不建议这样做。 像这样:
INSERT INTO dbo.t1_copy(Id,Name,Amount,Date)
SELECT * FROM(
INSERT INTO dbo.t1_copy(Id,Name,Amount,Date)
OUTPUT Inserted.id, Inserted.Name, Inserted.Amount, Inserted.Date
SELECT Id,Name,Amount,Date FROM dbo.t1) AS k
使用游标怎么办?
@GordonLinoff提到了在这种情况下使用Cursor的错误点,但是,如果您坚持使用Cursor,则需要在Fast_Forward
模式下声明游标。 在SCROLL
模式下进行声明将无济于事,并且会降低查询的总体性能!
DECLARE IDs CURSOR FAST_FORWARD FOR ...
性能比较:
如果仅看一下上述解决方案的执行计划,就会发现解决方案1与其他解决方案相比具有更好的性能输出。 在我的PC中,执行计划输出如下:
Solution 1 ====================> Subtree Cost: 0.0133
Solution 2 ====================> Subtree Cost: 0.0165
Solution 3 ====================> Subtree Cost: 0.0132*2=0.0264
Solution 4 ====================> Subtree Cost: 0.0232
Cursor in SCROLL mode =========> Subtree Cost: 0.0332
Cursor in Fast_Forward mode ===> Subtree Cost: 0.0203
这些数字在您的PC中会有所不同!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.