我试图将一些非常往返的重C#代码转换为实现表重新种子化的单个SQL脚本块。这是非生产代码,它基本上清除表中的测试数据并将它们作为测试套件的一部分重新安装。
当我尝试选择列名保存在变量中的标识列的最大值时出现问题(' @ IdentityColumnName'在下面的脚本中)。
执行此脚本时,我在包含MAX的行(@IdentityColumnName)上收到以下错误...
将数据类型varchar转换为bigint时出错。
...我假设正在发生这种情况,因为SQL假定我要求变量的MAX而不是将其视为列的名称。
-- Assume that some (or all) existing values have been removed from the table prior to this...
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '__Foo' AND COLUMNPROPERTY(OBJECT_ID(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1)
BEGIN
DECLARE @IdentityColumnName AS VARCHAR(MAX)
DECLARE @IdentityColumnValue AS BIGINT
SELECT TOP 1 @IdentityColumnName = [COLUMN_NAME] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME] = '__Foo'
SELECT @IdentityColumnValue = ISNULL(MAX(@IdentityColumnName), 0) FROM [__Foo]
-- Reseed the table with either 0 (if it's empty) or the maximum value already in the table
DBCC CHECKIDENT ('__Foo', RESEED, @IdentityColumnValue)
END
有没有人知道是否可以让SQL将该变量视为列的名称,以便我的查询有效?我已经尝试构建一个字符串并使用EXEC执行它,但这导致了捕获EXEC结果的严峻考验,我想确认没有更简单的方法来实现这一点。
答案 0 :(得分:0)
动态SQL代码段示例:
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'
DECLARE @IdentityColumnValue AS BIGINT;
SELECT @IdentityColumnValue = ISNULL(MAX(' + QUOTENAME(@IdentityColumnName) + N'), 0) FROM [__Foo];
DBCC CHECKIDENT (N''__Foo'', RESEED, @IdentityColumnValue);';
EXEC (@SQL);
答案 1 :(得分:0)
首先,您需要动态SQL。但是,您的转换问题发生在字符列上。你可以做这样的事情:
DECLARE @SQL NVARCHAR(MAX);
SET @SQL = N'SELECT @IdentityColumnValueStr := CAST(MAX(@IdentityColumnName) as NVARCHAR(MAX)) FROM [__Foo]';
SET @SQL = REPLACE(@SQL, '@IdentityColumnName', QUOTENAME(@IdentityColumnName));
DECLARE @IdentifyColumnValue NVARCHAR(MAX);
EXEC sp_executesql @SQL, N'@IdentityColumnValueStr NVARCHAR(MAX)', @IdentityColumnValueStr = @IdentityColumnValueStr;
PRINT @IdentityColumnValueStr;
如果您确实认为该值是数字,那么您可以非常小心地将值转换回数字。
答案 2 :(得分:0)
正如其他答案中所提到的,动态SQL是必需的,您不能让MAX将变量视为列名。我最终得到的解决方案是Dan和Gordon提供的解决方案的组合,并通过一些调整来实现我想要的目标。
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '__Foo' AND COLUMNPROPERTY(OBJECT_ID(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1)
BEGIN
DECLARE @SQL AS NVARCHAR(MAX), @IdentityColumnName AS NVARCHAR(MAX), @IdentityColumnValue AS BIGINT
-- Select the name of the first column into @IdentityColumnName (and just assume it's the identity column)
SELECT TOP 1 @IdentityColumnName = [COLUMN_NAME] FROM [INFORMATION_SCHEMA].[COLUMNS] WHERE [TABLE_NAME] = '__Foo'
-- Create a dynamic SQL statement to determine the maximum value in that column (or 0 if there are no rows and MAX returns NULL)
SELECT @SQL = 'SELECT @IdentityColumnValue = ISNULL(MAX(' + QUOTENAME(@IdentityColumnName) + '), 0) FROM [__Foo]'
-- Execute the dynamic SQL and put the result into the @IdentityColumnValue
EXEC sp_executesql @SQL, N'@IdentityColumnValue BIGINT OUTPUT', @IdentityColumnValue OUTPUT
-- Reseed the table using the value determined above
DBCC CHECKIDENT ('__Foo', RESEED, @IdentityColumnValue)
END