我正在学习如何使用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解决此错误?
答案 0 :(得分:3)
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;
答案 1 :(得分:1)
我的建议是编写返回表的功能 而不是使用插入选择语句
程序和功能之间的区别比你不能写
select procedure
但是
你可以写
选择功能
答案 2 :(得分:1)
只有动态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 :(得分:1)
我同意@EdHarper的说法,构建一个字符串然后运行sp_executesql可能是你最好的答案。
要记住的两件事我在前面的答案中看不到:
1)您之前可能已将数据复制到Master_copy数据库表中,因此在开始复制操作之前,可能需要删除目标表中的数据。
2)如果Master_copy表中有任何标识列(例如,因为您使用相同的Sql脚本生成Master_db和Master_copy表),那么您需要确保可以覆盖标识值(这可以通过以下方式完成) set identity_insert on命令。)
所以作为替代方案(没有必要重复另一个答案)并且如您所知,数据库名称可以简单地反规范化这种方法并为每个表编写一个简单的存储过程。
假设你有一张名为'person'的表,你可以写:
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
......等等每张桌子。