【问题标题】:Copy a Table's data from a Stored Procedure从存储过程中复制表的数据
【发布时间】:2010-04-23 08:36:09
【问题描述】:

我正在学习如何使用 SQL 和存储过程。我知道语法不正确:

使用存储过程将数据从一个表复制到另一个数据库的另一个表中。问题是我不知道要复制到哪个表或哪个数据库。我希望它使用参数而不是专门指定列。

我有 2 个数据库(Master_db 和 Master_copy),每个数据库上都有相同的表结构。

我想快速选择 Master_db 中的一个表,并将该表的数据复制到同名的 Master_copy 表中。我想出了这样的事情:

USE Master_DB
CREATE PROCEDURE TransferData
DEFINE @tableFrom, @tableTo, @databaseTo;

INSERT INTO @databaseTo.dbo.@databaseTo
SELECT * FROM Master_DB.dbo.@tableFrom
GO;

我能得到的最接近的是这个。现在的问题是我有一个 Timestamp 列并且出现了错误:

“无法将显式值插入时间戳列。将 INSERT 与列列表一起使用以排除时间戳列,或将 DEFAULT 插入时间戳列。”

USE Kenneth_Integration
GO
CREATE PROCEDURE TransferData
  @table  SYSNAME
  ,@databaseTo SYSNAME
AS
DECLARE @sql NVARCHAR(MAX)

SET @sql = 'DELETE FROM ' + @databaseTo + '..' + @table + ' set identity_insert ' + @databaseTo + '.dbo.' + @table + 
    ' on INSERT INTO ' + @databaseTo + '.dbo.' + @table + ' SELECT * FROM Kenneth_Integration.dbo.' + @table

EXEC sp_executesql @sql
GO

如何使用此 SP 解决此错误?

【问题讨论】:

  • 您是否考虑过如果您正在复制到可能已经包含您正在复制的一些数据的表中该怎么办?身份列也可能是一个问题。

标签: sql sql-server-2008 stored-procedures ssms


【解决方案1】:

SQL 查询中的对象名称不能以您尝试的方式参数化。

要使其工作,您需要使用动态 SQL:

USE Master_DB
CREATE PROCEDURE TransferData
 @tableFrom   SYSNAME
 ,@tableTo    SYSNAME
 ,@databaseTo SYSNAME
AS
DECLARE @sql NVARCHAR(MAX)
SET @sql = 'INSERT INTO ' + @databaseTo+ '.dbo.' + @tableTo + '
            SELECT * FROM Master_DB.dbo.' + @tableFrom

EXEC sp_executesql @sql
GO;

【讨论】:

  • “动态 SQL”对我来说是新事物,感谢您为我指明了正确的方向。我相信您的查询有一个错误。但是你的答案是正确的!错误(@databaseTo+ '.dbo.' + @databaseTo)
  • @Niike2 - 已更正。 (我从您的原始帖子中复制了错误)
  • 我建议在执行此类操作时在对象名称周围使用 QuoteName 函数。
【解决方案2】:

只有动态 SQL 允许变量作为表名。例如:

create procedure dbo.TransferData(
    @src varchar(50),
    @dest varchar(50))
as
declare @query varchar(500)
set @query = 'INSERT INTO ' + @src +
    'SELECT * FROM ' + @dest
exec @query
go

【讨论】:

    【解决方案3】:

    我同意@EdHarper 的观点,即构建一个字符串然后运行 ​​sp_executesql 可能是您最好的答案。

    我在之前的答案中看不到的两件事要记住:

    1) 您之前可能已经将数据复制到 Master_copy 数据库表中,因此您可能需要在开始复制操作之前删除目标表中的数据。

    2) 如果您在 Master_copy 表中有任何标识列(例如,因为您使用相同的 Sql 脚本生成 Master_db 和 Master_copy 表),那么您需要确保您可以覆盖标识值(这可以通过set identity_insert on 命令)。

    因此,作为替代方案(没有其他重复答案的意义),并且您知道数据库名称,您可以简单地对这种方法进行非规范化并为每个表编写一个简单的存储过程。

    假设您有一个名为“人”的表,您可以写:

    create procedure TransferDataPerson 
    as
    
    delete from Master_copy..Person
    
    set identity_insert Master_copy..Person on
    
    insert into Master_copy..Person
    select * from Master_db..Person
    

    ...对每个表以此类推。

    【讨论】:

    • 我已考虑您的观点并将其添加到查询中。谢谢,非常好的答案!现在问题已添加到此页面上的答案中。
    【解决方案4】:

    我的建议是编写返回表的函数 而不是使用插入选择语句

    过程和函数之间的区别比你写不出来 select procedure 但是 你可以写 选择功能

    【讨论】:

    • 好的,但这对我没有多大帮助,因为我有 SQL 语言问题,而且我认为语法非常错误。而且我不知道这是否可能?
    猜你喜欢
    • 1970-01-01
    • 2012-07-04
    • 2020-01-28
    • 2010-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 1970-01-01
    相关资源
    最近更新 更多