使用游标将数据两次插入同一个表中

时间:2018-05-12 07:54:20

标签: sql sql-server cursor

我有两个表cursor_createdcursor_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

1 个答案:

答案 0 :(得分:0)

您只需在光标内按如下所示重写您的插入内容:

INSERT INTO cursor_copied (id, name, amount, date)
    VALUES (@ID, @Name, @Amount, @Date),
           (@ID, @Name, @Amount, @Date)

但是,您选择的解决方案可能不是解决此类问题的好方法。如果您对其他解决方案感兴趣,请阅读以下故事。

解决方案1 ​​

参考@GordonLinoff's答案

解决方案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 KeyIdentity列(如果存在)!

解决方案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上会有所不同!