这是一个创建数据库的存储过程的代码片段。我们有一个具有唯一标识符PK的表。我试图插入一行具有空guid的PK:
DECLARE @MailingListId uniqueidentifier
SET @MailingListId = (SELECT cast('00000000-0000-0000-0000-000000000000' AS uniqueidentifier))
DECLARE @MailingListName varchar(15)
SET @MailingListName = 'General'
SET @str = ('INSERT [' + @db_name + '].[dbo].[MailingLists] ([MailingListId], [MailingListName], [Selected])
VALUES (' + @MailingListId + ', ''' + @MailingListName + ''', 0)')
exec (@str);
错误信息是
Msg 156, Level 15, State 1, Line 1198
Incorrect syntax near the keyword 'VALUES'.
Msg 105, Level 15, State 1, Line 1198
Unclosed quotation mark after the character string ')
看不出VALUES子句有什么问题,但我猜它与最后的报价有关,尽管最后的报价是结束报价而不是开始报价。也许是我给@MailingListId
赋空指针的方式?应该引用@MailingListId
吗?
您应该使用QUOTENAME
作为数据库名称,并通过sp_executesql
使用适当的参数。您也可以将空指南缩短为CAST(0x0 AS uniqueidentifier)
DECLARE @MailingListId uniqueidentifier = cast(0x0 AS uniqueidentifier);
DECLARE @MailingListName varchar(15) = 'General';
DECLARE @str nvarchar(max) =
N'INSERT ' + QUOTENAME(@db_name) + N'.[dbo].[MailingLists] ([MailingListId], [MailingListName], [Selected])
VALUES (@MailingListId,@MailingListName, 0);';
PRINT @str; -- for debugging
exec sp_executesql
@str,
N'@MailingListId uniqueidentifier, @MailingListName varchar(15)',
@MailingListId = @MailingListId, @MailingListName = @MailingListName;
您可以通过使用PRINT
语句将其打印出来来调试动态SQL -然后您可以调试静态SQL。
你的SQL张贴实际上不工作,它给出了一个错误:
添加操作符中的数据类型varchar和uniqueidentifier不兼容。
因为您正在尝试将@MailingListId
连接到动态SQL字符串中。如果你从一开始就把它设为字符串的话
当插入uniqueidentifier
时,你需要引用它,这是你正在做的。
DECLARE @db_name VARCHAR(32) = 'MyDatabase', @str NVARCHAR(MAX);
-- No point declaring as uniqueidentifier when you then have to convert back to a string to concatenate below
DECLARE @MailingListId VARCHAR(38) = '00000000-0000-0000-0000-000000000000';
DECLARE @MailingListName VARCHAR(15) = 'General';
SET @str = 'INSERT ' + QUOTENAME(@db_name) + '.[dbo].[MailingLists] ([MailingListId], [MailingListName], [Selected])
VALUES (''' + @MailingListId + ''', ''' + @MailingListName + ''', 0)';
--EXEC (@str);
PRINT (@str);
注意使用QUOTENAME
来防止SQL注入。
给出以下有效的SQL:
INSERT [MyDatabase].[dbo].[MailingLists] ([MailingListId], [MailingListName], [Selected])
VALUES ('00000000-0000-0000-0000-000000000000', 'General', 0);
毕竟你应该按照Charlieface的建议去做。但我将把它留在这里,因为你仍然可以从中学到一些东西。