【问题标题】:Select Into From, Create table without identity property选择进入,创建没有身份属性的表
【发布时间】:2012-09-22 14:14:22
【问题描述】:

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

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)

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

【问题讨论】:

  • 使用INSERT INTO tablename (list of columns - without the IDENTITY) SELECT ...?
  • 为什么选择和进入同一张表?
  • 使用插入到历史表中的触发器用于'on insert'。
  • 这个过程对所有表都是通用的,我不能使用列名。应该创建标识列但没有标识属性。
  • 如果您使用 *,则将始终复制身份属性。无论如何,这看起来是个可怕的主意。

标签: sql sql-server


【解决方案1】:

有一些生活窍门

select *
into #tmp_table
from Table

union all

select *
from Table 
where 1<>1

使用 union all deprecated 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.

【讨论】:

    【解决方案2】:

    您的代码看起来像是在尝试保留数据更改的历史记录。考虑使用Change Data Capture 而不是滚动您自己的解决方案。

    允许插入指定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 变得非常繁琐。

    【讨论】:

    • 或者 AutoAudit 如果在不支持 CDC 的版本上
    【解决方案3】:

    Andomar 是对的,如果你可以使用Change Data Capture,你应该这样做。但是,如果您卡在不支持它的版本上,您仍然可以解决此问题。

    根据Microsoft...

    当一个现有的标识列被选择到一个新表中时,新的 列继承 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
    

    【讨论】:

      【解决方案4】:

      尝试以下查询:我发现这个查询正常。这将选择没有身份 = 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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-08-13
        • 1970-01-01
        • 1970-01-01
        • 2011-01-10
        • 2011-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多