4

我有这样的存储过程,在任何表的插入命令之后执行

Create Procedure [dbo].[HistoryInsert](
@TableName  nVarchar(500),
@RecordId   bigInt
)
As

    declare @Query  nVarChar(max)
    if Not Exists (Select   Top 1 1
                From    Information_schema.tables
                Where   Table_Name  = @TableName + 'History')
        Set @Query  = 'Select  *  Into ' + @TableName + 'History FROM ' + @TableName

    Else
        Set @Query  = 'Insert Into ' + @TableName  + 'History Select *   FROM ' + @TableName
        Exec(@Query)

    Exec(@Query)

首次执行此过程时,会创建历史记录表。并且当此过程第二次执行时,插入失败,因为创建的表具有标识列。如何从表中选择所有列而不增加列的标识属性。

4

4 回答 4

7

有一些救生窍门

select *
into #tmp_table
from Table

union all

select *
from Table 
where 1<>1

使用 union all 也弃用 SQL Endgine 来继承约束和标识。

      When an existing identity column is selected into a new table, the new column inherits the IDENTITY property, unless one of the following conditions is true:
            - The SELECT statement contains a join, GROUP BY clause, or aggregate function.
            - Multiple SELECT statements are joined by using UNION.
            - The identity column is listed more than one time in the select list.
            - The identity column is part of an expression.
            - The identity column is from a remote data source.
于 2019-08-15T11:54:31.813 回答
4

您的代码看起来像是试图保留数据更改的历史记录。考虑使用变更数据捕获而不是滚动您自己的解决方案。

允许插入identity指定列的一种方法是identity_insert

SET IDENTITY_INSERT TableName ON

你可以在你的第二个执行官中打开它。由于您要复制整个表,因此您必须在复制之前清除历史记录表,例如使用truncate

Set @Query  = 
    'truncate table ' + @TableName  + 'History; ' +
    'set identity_insert ' + @TableName 'History on; ' +
    'Insert Into ' + @TableName  + 'History Select *   FROM ' + @TableName '; ' +
    'set identity_insert ' + @TableName 'History off; '

一个更好的解决方案是修改第一个 exec 以创建一个没有identity列的表。我还没有找到一种实用的方法来做到这一点。SQL Server 要求您删除该列并重新创建它,这将使动态 SQL 变得非常繁琐。

于 2012-09-22T14:35:24.333 回答
0

Andomar 是对的,如果您可以使用变更数据捕获,您应该这样做。但是,如果您遇到不支持它的版本,您仍然可以解决此问题。

根据微软...

将现有标识列选择到新表中时,新列将继承 IDENTITY 属性,除非以下条件之一为真:

  • SELECT 语句包含连接、GROUP BY 子句或聚合函数。
  • 使用 UNION 连接多个 SELECT 语句。
  • 标识列在选择列表中多次列出。
  • 标识列是表达式的一部分。
  • 标识列来自远程数据源。

因此,例如,如果您知道标识列的名称,则可以执行以下操作而无需知道任何其他列:

Exec('select ' + @identityColName + ' as id_temp123, * into ' + @TableName  + 'History from ' + @TableName)
Exec('alter table ' + @TableName  + ' drop column id_temp123')

这也保留了列顺序。

您可以通过查看信息架构以编程方式找到标识列(如果有的话)。例如:

select TABLE_NAME + '.' + COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS 
where 
    TABLE_SCHEMA = 'dbo' and 
    TABLE_NAME = 'MyTable' and 
    columnProperty(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') = 1
于 2014-10-13T07:07:50.553 回答
0

试试下面的查询:我发现这个工作正常。这将选择没有标识 = 1 的列中的数据

DECLARE @Temp NVARCHAR(MAX); 
DECLARE @SQL NVARCHAR(MAX);

SET @Temp = '';
SELECT @Temp = @Temp + COLUMN_NAME + ', ' FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='Person' AND  columnProperty(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') != 1 

SET @SQL = 'SELECT ' + SUBSTRING(@Temp, 0, LEN(@Temp)) +' FROM [Person]';
EXECUTE SP_EXECUTESQL @SQL;

您可以从 sys.columns 表中获取列名详细信息

尝试以下查询:

SELECT * FROM SYS.COLUMNS 
WHERE object_id = OBJECT_ID('dbo.TableName') 
AND [Name] <> 'ColumnName'

DECLARE @sql as VARCHAR(8000)
SET @sql = 'SELECT '

SELECT @sql += [Name] + ', ' FROM SYS.COLUMNS 
WHERE object_id = OBJECT_ID('dbo.TableName') 
AND [Name] <> 'ColumnName'

SELECT @sql += ' FROM Dbo.TableName'

EXEC(@sql)
于 2020-09-22T17:03:09.690 回答