2016-12-18 14 views
0

我試圖將一些非常往返繁重的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結果的困難,我想確認沒有更簡單的方法來實現這一點。

  • 如果這樣做會產生影響,代碼將需要對SQL Server 2008 R2起作用。
  • 這只是非生產測試的東西;它不必遵守任何最佳實踐。
  • 通常會有一個DELETE FROM和可選的WHERE xyz在種子之前立即執行。有時桌子最後是空的,有時候它還有幾排。
+0

如果您希望列是動態的,則需要使用動態SQL。 –

+0

'\t SET @SQL = N' \t \t DECLARE @IdentityColumnValue AS BIGINT; \t \t SELECT @IdentityColumnValue = ISNULL(MAX( '+ QUOTENAME(@IdentityColumnName)+ N '),0)FROM [__Foo] \t \t DBCC CHECKIDENT(N' '__富'',RESEED,@IdentityColumnValue);'; \t EXEC(@SQL);' –

回答

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 
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); 
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; 

您的然後非常仔細地將該值轉換回數字,如果你真的相信的值是數字。