Мне нужен запрос, который получает тип данных, максимальную длину, если это тождество и если это первичный ключ из определенного table_name без использования функции object_id. Итак, что я имею сейчас (и также нашел это где-то в stackoverflow):
SELECT col.COLUMN_NAME AS ColumnName
, col.DATA_TYPE AS DataType
, col.CHARACTER_MAXIMUM_LENGTH AS MaxLength
, COLUMNPROPERTY(OBJECT_ID('[' + col.TABLE_SCHEMA + '].[' + col.TABLE_NAME + ']'), col.COLUMN_NAME, 'IsIdentity')AS IS_IDENTITY
, CAST(ISNULL(pk.is_primary_key, 0)AS bit)AS IsPrimaryKey
FROM INFORMATION_SCHEMA.COLUMNS AS col
LEFT JOIN(SELECT SCHEMA_NAME(o.schema_id)AS TABLE_SCHEMA
, o.name AS TABLE_NAME
, c.name AS COLUMN_NAME
, i.is_primary_key
FROM sys.indexes AS i JOIN sys.index_columns AS ic ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
JOIN sys.objects AS o ON i.object_id = o.object_id
LEFT JOIN sys.columns AS c ON ic.object_id = c.object_id
AND c.column_id = ic.column_id
WHERE i.is_primary_key = 1)AS pk ON col.TABLE_NAME = pk.TABLE_NAME
AND col.TABLE_SCHEMA = pk.TABLE_SCHEMA
AND col.COLUMN_NAME = pk.COLUMN_NAME
WHERE col.TABLE_NAME = 'tbl_users'
ORDER BY col.TABLE_NAME, col.ORDINAL_POSITION;
Я использую этот код для курсора, и когда я пытаюсь получить значение IS_IDENTITY, оно всегда пустое или что-то в этом роде. Я чувствую, что динамический SQL и курсор не нравится функция OBJECT_ID. Когда я запускаю этот запрос без курсора и прочего, он отлично работает.
ПОЛНЫЙ КОД:
ALTER Procedure [dbo].[sp_generateUpserts]
@databaseName nvarchar(MAX)
AS
BEGIN
SET NOCOUNT ON
DECLARE @tranState BIT
IF @@TRANCOUNT = 0
BEGIN
SET @tranState = 1
BEGIN TRANSACTION tranState
END
BEGIN TRY
Declare @TABLE_NAME varchar(100)
Declare @COLUMN_NAME varchar(100)
Declare @COLUMN_NAME_WITH_SPACE varchar(100)
Declare @DATA_TYPE varchar(100)
Declare @CHARACTER_MAXIMUM_LENGTH INT
Declare @IS_PK INT
Declare @IS_IDENTITY INT
DECLARE @statement nvarchar(MAX)
SET @statement = N'USE [' + @databaseName + '];
DECLARE cursorUpsert CURSOR FOR
SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
ORDER BY TABLE_NAME'
EXECUTE sp_executesql @statement
DECLARE @use_db nvarchar(max)
DECLARE @generateSpStatement varchar(MAX)
DECLARE @spParameters varchar(MAX) = ''
DECLARE @whereColumns varchar(MAX) = ''
DECLARE @updateStatement varchar(MAX) = ''
DECLARE @insertStatement varchar(MAX) = ''
DECLARE @valueStatement varchar(MAX) = ''
OPEN cursorUpsert
FETCH NEXT FROM cursorUpsert
INTO @TABLE_NAME
WHILE @@FETCH_STATUS = 0
BEGIN
DECLARE @statementColumns nvarchar(MAX)
SET @statementColumns = N'USE [' + @databaseName + '];
DECLARE cursorUpsertColumns CURSOR FOR
SELECT col.COLUMN_NAME
, col.DATA_TYPE
, col.CHARACTER_MAXIMUM_LENGTH
, COLUMNPROPERTY(OBJECT_ID(QUOTENAME(col.TABLE_SCHEMA) + ''.'' + QUOTENAME(col.TABLE_NAME)), col.COLUMN_NAME, ''IsIdentity'')AS IS_IDENTITY
, CAST(ISNULL(pk.is_primary_key, 0) AS bit) AS IS_PK
FROM INFORMATION_SCHEMA.COLUMNS AS col
LEFT JOIN(SELECT SCHEMA_NAME(o.schema_id)AS TABLE_SCHEMA
, o.name AS TABLE_NAME
, c.name AS COLUMN_NAME
, i.is_primary_key
FROM sys.indexes AS i JOIN sys.index_columns AS ic ON i.object_id = ic.object_id
AND i.index_id = ic.index_id
JOIN sys.objects AS o ON i.object_id = o.object_id
LEFT JOIN sys.columns AS c ON ic.object_id = c.object_id
AND c.column_id = ic.column_id
WHERE i.is_primary_key = 1)AS pk ON col.TABLE_NAME = pk.TABLE_NAME
AND col.TABLE_SCHEMA = pk.TABLE_SCHEMA
AND col.COLUMN_NAME = pk.COLUMN_NAME
WHERE col.TABLE_NAME = ''' + @TABLE_NAME + '''
ORDER BY col.TABLE_NAME, col.ORDINAL_POSITION;'
EXECUTE sp_executesql @statementColumns
OPEN cursorUpsertColumns
FETCH NEXT FROM cursorUpsertColumns
INTO @COLUMN_NAME, @DATA_TYPE, @CHARACTER_MAXIMUM_LENGTH, @IS_IDENTITY, @IS_PK
WHILE @@FETCH_STATUS = 0
BEGIN
-- Parameters for the SP
IF @COLUMN_NAME LIKE '% %'
BEGIN
SET @COLUMN_NAME_WITH_SPACE = @COLUMN_NAME
SET @COLUMN_NAME_WITH_SPACE = REPLACE(@COLUMN_NAME_WITH_SPACE,' ','_')
SET @spParameters = @spParameters + CHAR(13) + '@' + @COLUMN_NAME_WITH_SPACE + ' ' + @DATA_TYPE
END
ELSE
BEGIN
SET @spParameters = @spParameters + CHAR(13) + '@' + @COLUMN_NAME + ' ' + @DATA_TYPE
END
IF @DATA_TYPE IN ('varchar', 'nvarchar', 'char', 'nchar')
BEGIN
IF @CHARACTER_MAXIMUM_LENGTH = '-1'
BEGIN
SET @spParameters = @spParameters + '(MAX)'
END
ELSE
BEGIN
SET @spParameters = @spParameters + '(' + CAST(@CHARACTER_MAXIMUM_LENGTH As Varchar(10)) + ')'
END
END
-- Add a comma after each parameter
SET @spParameters = @spParameters + ', '
IF @COLUMN_NAME IN ('top')
BEGIN
IF @IS_IDENTITY != 1
BEGIN
print('YES IDENTITY')
END
-- Add where parameters: ColumnName=@ColumnName AND
SET @whereColumns = @whereColumns + CHAR(32) + '[' + @COLUMN_NAME + ']=@' + @COLUMN_NAME + ' AND'
-- Add update parameters: column1 = value1, etc.
IF @IS_IDENTITY != 1 OR @IS_PK != 1
BEGIN
SET @updateStatement = @updateStatement + CHAR(32) + '[' + @COLUMN_NAME + ']=@' + @COLUMN_NAME + ','
END
-- Add insert columns
SET @insertStatement = @insertStatement + CHAR(32) + '[' + @COLUMN_NAME + '],'
-- Add values
SET @valueStatement = @valueStatement + CHAR(32) + '@' + @COLUMN_NAME + ','
END
ELSE IF @COLUMN_NAME LIKE '% %'
BEGIN
IF @IS_IDENTITY != 1
BEGIN
print('YES IDENTITY')
END
-- Add where parameters: ColumnName=@ColumnName AND
SET @whereColumns = @whereColumns + CHAR(32) + '[' + @COLUMN_NAME + ']=@' + @COLUMN_NAME_WITH_SPACE + ' AND'
-- Add update parameters: column1 = value1, etc.
IF @IS_IDENTITY != 1 OR @IS_PK != 1
BEGIN
SET @updateStatement = @updateStatement + CHAR(32) + '[' + @COLUMN_NAME + ']=@' + @COLUMN_NAME_WITH_SPACE + ','
END
-- Add insert columns
SET @insertStatement = @insertStatement + CHAR(32) + '['+ @COLUMN_NAME + '],'
-- Add values
SET @valueStatement = @valueStatement + CHAR(32) + '@' + @COLUMN_NAME_WITH_SPACE + ','
END
ELSE
BEGIN
IF @IS_IDENTITY != 1
BEGIN
print('YES IDENTITY')
END
-- Add where parameters: ColumnName=@ColumnName AND
SET @whereColumns = @whereColumns + CHAR(32) + @COLUMN_NAME + '=@' + @COLUMN_NAME + ' AND'
-- Add update parameters: column1 = value1, etc.
IF @IS_IDENTITY != 1 OR @IS_PK != 1
BEGIN
SET @updateStatement = @updateStatement + CHAR(32) + @COLUMN_NAME + '=@' + @COLUMN_NAME + ','
END
-- Add insert columns
SET @insertStatement = @insertStatement + CHAR(32) + @COLUMN_NAME + ','
-- Add values
SET @valueStatement = @valueStatement + CHAR(32) + '@' + @COLUMN_NAME + ','
END
FETCH NEXT FROM cursorUpsertColumns
INTO @COLUMN_NAME, @DATA_TYPE, @CHARACTER_MAXIMUM_LENGTH, @IS_IDENTITY, @IS_PK
if @@FETCH_STATUS!=0
begin
-- Last row, remove things
-- Remove the last AND word
SET @whereColumns = left (@whereColumns, len(@whereColumns) -3)
-- Remove the last comma from the parameter
SET @spParameters = left (@spParameters, len(@spParameters) -1)
-- Remove the last comma from the updateStatement
SET @updateStatement = left (@updateStatement, len(@updateStatement) -1)
-- Remove the last comma from the insertStatement
SET @insertStatement = left (@insertStatement, len(@insertStatement) -1)
-- Remove the last comma from the valueStatement
SET @valueStatement = left (@valueStatement, len(@valueStatement) -1)
end
END;
CLOSE cursorUpsertColumns;
DEALLOCATE cursorUpsertColumns;
--- End Cursor Columns
-- Generate the SP
SET @generateSpStatement = 'CREATE Procedure [dbo].[sp_' + @TABLE_NAME + '_upsert]' + @spParameters
SET @generateSpStatement = @generateSpStatement + CHAR(13) + 'AS BEGIN' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'SET NOCOUNT ON' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'DECLARE @tranState BIT' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'IF @@TRANCOUNT = 0' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'BEGIN' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + CHAR(9) +'SET @tranState = 1' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + CHAR(9) +'set transaction isolation level serializable' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + CHAR(9) +'BEGIN TRANSACTION tranState' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'END' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(13) + 'BEGIN TRY' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'IF EXISTS(SELECT 1 FROM ' + @TABLE_NAME + ' WITH (updlock) WHERE' + @whereColumns + ')' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + CHAR(9) + 'UPDATE ' + @TABLE_NAME + ' SET' + @updateStatement + ' WHERE ' + @whereColumns + ';' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'ELSE' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + CHAR(9) + 'INSERT INTO ' + @TABLE_NAME + ' ('+ @insertStatement + ') VALUES (' + @valueStatement + ');' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'IF @tranState = 1 AND XACT_STATE() = 1' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + CHAR(9) + 'COMMIT TRANSACTION tranState' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + 'END TRY' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(13) + 'BEGIN CATCH' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'DECLARE @Error_Message VARCHAR(5000)' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'DECLARE @Error_Severity INT' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'DECLARE @Error_State INT' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'SELECT @Error_Message = ERROR_MESSAGE()' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'SELECT @Error_Severity = ERROR_SEVERITY()' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'SELECT @Error_State = ERROR_STATE()' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'IF @tranState = 1 AND XACT_STATE() <> 0' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + CHAR(9) +'ROLLBACK TRANSACTION' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(9) + 'RAISERROR (@Error_Message, @Error_Severity, @Error_State)' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + 'END CATCH' + CHAR(13)
SET @generateSpStatement = @generateSpStatement + CHAR(13)
SET @generateSpStatement = @generateSpStatement + 'END' + CHAR(13)
--print(@generateSpStatement)
-- Reset Variables
SET @generateSpStatement = ''
SET @spParameters = ''
SET @whereColumns = ''
SET @updateStatement = ''
SET @insertStatement = ''
SET @valueStatement = ''
FETCH NEXT FROM cursorUpsert
INTO @TABLE_NAME
END;
CLOSE cursorUpsert;
DEALLOCATE cursorUpsert;
IF @tranState = 1
AND XACT_STATE() = 1
COMMIT TRANSACTION tranState
END TRY
BEGIN CATCH
DECLARE @Error_Message VARCHAR(5000)
DECLARE @Error_Severity INT
DECLARE @Error_State INT
SELECT @Error_Message = ERROR_MESSAGE()
SELECT @Error_Severity = ERROR_SEVERITY()
SELECT @Error_State = ERROR_STATE()
IF @tranState = 1 AND XACT_STATE() <> 0
ROLLBACK TRANSACTION
RAISERROR (@Error_Message, @Error_Severity, @Error_State)
END CATCH
END