T-SQL开发-10.IDENTITY属性使用小结
从SQL Server 2012开始有了Sequence,简单用列如下: CREATESEQUENCETestSeqSTARTWITH1INCREMENTBY1;SELECTNEXTVALUEFORTestSeqASNextValue; 在这之前,表中生成序列号大多都是借助IDENTITY列属性,当然也有一些时候,是在自定义表中,自己维护序列号。 一.
从SQL Server 2012开始有了Sequence,简单用列如下:
CREATE SEQUENCE TestSeq START WITH 1 INCREMENT BY 1; SELECT NEXT VALUE FOR TestSeq AS NextValue;
在这之前,表中生成序列号大多都是借助IDENTITY列属性,当然也有一些时候,是在自定义表中,自己维护序列号。
一. 创建IDENTITY列
if OBJECT_ID('test','U') is not null drop table test GO create table test(id int identity, c1 char(1)) insert test values('a'); insert test values('b'); select * from test
1. 没有指定IDENTITY(seed ,increment),默认就是 IDENTITY(1, 1),效果同如下语句
create table test(id int identity(1,1), c1 char(1))
2. 通过函数或者系统视图,都可以查看是否为IDENTITY列
SELECT COLUMNPROPERTY(OBJECT_ID('test'),'id','IsIdentity') AS is_identity select object_name(object_id) as table_name, is_identity,* from sys.columns where object_id=object_id('test') --and is_identity=1
3. 重置IDENTITY列的初始值,通常在数据删除/归档后进行
DELETE test DBCC CHECKIDENT('test', RESEED, 1) DBCC CHECKIDENT('test', NORESEED) --TRUNCATE表后会自动重置IDENTITY列 TRUNCATE TABLE test DBCC CHECKIDENT('test', NORESEED)
二. 获取IDENTITY列值
插入了数据,有时还需要获取刚才生成的序列值另作他用,返回给前端也好,或者插入其他将来需要关联的表。
记得曾经有个面试题:假设当前表IDENTITY列最大值为N,在存储过程中,对这个表插入1行数据,获取到的IDENTITY列值有时小于或者大于N+1,可能是什么原因?
获取IDENTITY列值有三种方式:
(1) IDENT_CURRENT( 'table_name' ) 返回为任何会话和任何作用域中的特定表最后生成的标识值。
(2) @@IDENTITY 返回为当前会话的所有作用域中的任何表最后生成的标识值。
(3) SCOPE_IDENTITY() 返回为当前会话和当前作用域中的任何表最后生成的标识值。
IDENT_CURRENT( 'table_name' ) 针对特定表,是全局的。@@IDENTITY和SCOPE_IDENTITY()针对所有表,区别在于作用域,也就是上下文:
(1) 如果当前INSERT语句上有函数,触发器等(不同作用域的)对象返回的IDENTITY值,那么@@IDENTITY会取所有表上的最后1个,而不是当前表上的;
(2) SCOPE_IDENTITY()会取当前作用域所有表上最后1个IDENTITY值,被调用的函数,触发器已经超出了作用域/上下文。所以在使用INSERT后,接着使用SCOPE_IDENTITY()获取IDENTITY列值,就不会有问题了:
insert test values('z'); select SCOPE_IDENTITY() as curr_value
一个GO语句/批处理,也是一个上下文的分界点,但是SQL语句是顺序执行的,所以一个会话里,只要在INSERT之后用SCOPE_IDENTITY()来获取IDENTITY值是没问题的。
三. 修改IDENTITY列值/属性
1. 对已存在的列增加/删除IDENTITY属性
if OBJECT_ID('t_id') is not null drop table t_id GO create table t_id(id int,c1 char(1)) insert into t_id select 1,'a' union all select 2,'b' alter table t_id alter column id int identity(1,2) /* Msg 156, Level 15, State 1, Line 2 Incorrect syntax near the keyword 'identity'. */
直接修改列属性会报错,IDENTITY属性只能伴随着列增加/删除。
(1) 利用中间表
在SSMS界面上设计表(SSMS/Tables/Design),可以直接增加/删除列上的IDENTITY属性,如果生成脚本看看的话(右击编辑框/工具栏/菜单栏),可以发现SSMS是利用了中间表,并非在原表直接修改属性。
表上有约束,索引等对象时,脚本会更加繁杂些。示例如下图:
如果出现如下错误:
Saving changes is not permitted. The changes that you have made require the following tables to be dropped and re-created. You have either made changes to a table that can't be re-created or enabled the option Prevent saving changes that require the table to be re-created.
是因为SSMS里有个选项没设置,SQL Server认为有删除/重建表的脚本不安全,所以默认关闭了,需要手动开启一下,去掉那个勾:
对表上已存在列添加IDENTITY属性,生成的脚本如下:
BEGIN TRANSACTION SET QUOTED_IDENTIFIER ON SET ARITHABORT ON SET NUMERIC_ROUNDABORT OFF SET CONCAT_NULL_YIELDS_NULL ON SET ANSI_NULLS ON SET ANSI_PADDING ON SET ANSI_WARNINGS ON COMMIT BEGIN TRANSACTION GO CREATE TABLE dbo.Tmp_t_id ( id int NOT NULL IDENTITY (1, 1), c1 char(1) NULL ) ON [PRIMARY] GO ALTER TABLE dbo.Tmp_t_id SET (LOCK_ESCALATION = TABLE) GO SET IDENTITY_INSERT dbo.Tmp_t_id ON GO IF EXISTS(SELECT * FROM dbo.t_id) EXEC('INSERT INTO dbo.Tmp_t_id (id, c1) SELECT id, c1 FROM dbo.t_id WITH (HOLDLOCK TABLOCKX)') GO SET IDENTITY_INSERT dbo.Tmp_t_id OFF GO DROP TABLE dbo.t_id GO EXECUTE sp_rename N'dbo.Tmp_t_id', N't_id', 'OBJECT' GO COMMIT
对表上已存在列删除IDENTITY属性,生成的脚本如下:
BEGIN TRANSACTION SET QUOTED_IDENTIFIER ON SET ARITHABORT ON SET NUMERIC_ROUNDABORT OFF SET CONCAT_NULL_YIELDS_NULL ON SET ANSI_NULLS ON SET ANSI_PADDING ON SET ANSI_WARNINGS ON COMMIT BEGIN TRANSACTION GO CREATE TABLE dbo.Tmp_t_id ( id int NOT NULL, c1 char(1) NULL ) ON [PRIMARY] GO ALTER TABLE dbo.Tmp_t_id SET (LOCK_ESCALATION = TABLE) GO IF EXISTS(SELECT * FROM dbo.t_id) EXEC('INSERT INTO dbo.Tmp_t_id (id, c1) SELECT id, c1 FROM dbo.t_id WITH (HOLDLOCK TABLOCKX)') GO DROP TABLE dbo.t_id GO EXECUTE sp_rename N'dbo.Tmp_t_id', N't_id', 'OBJECT' GO COMMIT
(2) 利用中间列
对表上已存在列删除IDENTITY属性
if OBJECT_ID('t_id') is not null drop table t_id GO create table t_id(id int identity(1,1),c1 char(1)) insert into t_id select 'a' union all select 'b' select * from t_id SELECT COLUMNPROPERTY(OBJECT_ID('t_id'),'id','IsIdentity') --在表上新增一个列,把IDENTITY列值复制过去 alter table t_id add id_new int GO update t_id set id_new = id --删除原来的列,并重命名新增列 alter table t_id drop column id exec sp_rename 't_id.id_new','id' select * from t_id SELECT COLUMNPROPERTY(OBJECT_ID('t_id'),'id','IsIdentity')
对表上已存在列添加IDENTITY属性,用中间列的方式不太可行,因为IDENTITY列不接受UPDATE,新增的IDENTITY列无法直接复制原id的值,还得借助中间表,但如果不需要原来id的值,那么可以:
if OBJECT_ID('t_id') is not null drop table t_id GO create table t_id(id int,c1 char(1)) insert into t_id select 1,'a' union all select 3,'b' select * from t_id SELECT COLUMNPROPERTY(OBJECT_ID('t_id'),'id','IsIdentity') --在表上新增一个IDENTITY列,不复制原来的ID值 alter table t_id add id_new int identity(1,1) not null --删除原来的列,并重命名新增列 alter table t_id drop column id exec sp_rename 't_id.id_new','id' select * from t_id SELECT COLUMNPROPERTY(OBJECT_ID('t_id'),'id','IsIdentity')
2. 在IDENTITY列上做增删改操作(DML)
(1) 删除操作没有问题,直接DELETE即可
delete test where id = 2
(2) 如果要显式INSERT某个值,需要开启IDENTITY_INSERT这个SESSION级的选项
set IDENTITY_INSERT test on; insert test(id,c1) values(3,'c'); set IDENTITY_INSERT test off; select * from test
(3) 如果要UPDATE IDENTITY列值,无论是否开启IDENTITY_INSERT这个选项都无法更新
set IDENTITY_INSERT test on; update test set id = 10 where id = 1 set IDENTITY_INSERT test off; /* Msg 8102, Level 16, State 1, Line 1 Cannot update identity column 'id'. */
非要修改的话,就得借助中间表,在不含IDENTITY属性的中间表里做完UPDATE,然后再把数据导回来。中间表可参考上面的脚本。
3. IDENTITY列属性复制
(1) 直接从单表SELECT INTO table_name,原表其他约束,索引等等都不会被复制,但是IDENTITY属性会被复制。
select * into test2 from test select * from test2 select columnproperty(OBJECT_ID('test'),'id','IsIdentity') select columnproperty(OBJECT_ID('test2'),'id','IsIdentity')
(2) 如果有IDENTITY属性的表和其他表JOIN,那么IDENTITY属性不会被复制。
select a.* into test3 from test a inner join sys.objects b on a.id = b.object_id select * from test3 select columnproperty(OBJECT_ID('test3'),'id','IsIdentity')
假如复制表时,不想要IDENTITY属性,正好可以利用一下这个特点,如下:
select a.* into test4 from test a inner join sys.objects b on 1=2
(3) 如果用SELECT INTO table_name导数据时,FROM子句有多表关联,且想要保留IDENTITY属性,这时可以用INSERT,并考虑使用TABLOCK提示
if OBJECT_ID('test5','U') is not null drop table test5 GO create table test5(id int identity, c1 char(1)) select * from test5 GO set IDENTITY_INSERT test5 on; insert into test5 WITH(TABLOCK) (id,c1) select a.* from test a inner join test2 b on a.id = b.id set IDENTITY_INSERT test5 off; select * from test5 select columnproperty(OBJECT_ID('test5'),'id','IsIdentity')
这里使用了WITH(TABLOCK)选项,在SIMPLE或者BULK_LOGGED恢复模式下,SELECT…INTO table_name和INSERT INTO table_name WITH(TABLOCK)都能最小化日志。
4. 借助SWITCH来处理IDENTITY属性,推荐
同样也是利用中间表,上面的几个列子都使用了INSERT,这里使用SWITCH,不再有数据倒来倒去的开销,需要SQL Server 2008及以上版本,能比较有效地同时解决上面的3个问题:
(1) 不能直接对表上现有列增加/删除IDENTITY属性;
(2) 不能直接更新IDENTITY列;
(3) 复制表时,有选择的复制IDENTITY列属性(多表关联,对关联后的表做SWITCH以实现);
CREATE TABLE Temp1 ( ID INT IDENTITY(1,1) PRIMARY KEY, X VARCHAR(10) ) INSERT INTO Temp1 OUTPUT INSERTED.* SELECT 'Foo' UNION ALL SELECT 'Bar' UNION ALL SELECT 'Baz' CREATE TABLE Temp2 ( ID INT PRIMARY KEY, X VARCHAR(10) ) ALTER TABLE Temp1 SWITCH TO Temp2; SELECT COLUMNPROPERTY(OBJECT_ID('Temp1'),'id','IsIdentity') SELECT COLUMNPROPERTY(OBJECT_ID('Temp2'),'id','IsIdentity') INSERT INTO Temp2 OUTPUT INSERTED.* SELECT 10,'Foo' UNION ALL SELECT 20,'Bar' UNION ALL SELECT 5, 'Baz' UPDATE Temp2 SET ID = ID + 1; ALTER TABLE Temp2 SWITCH TO Temp1; SELECT * FROM Temp2 SELECT * FROM Temp1
另外,从SQL Server 2012开始,如果开发时使用了SEQUENCE,这些IDENTITY列的限制就都不会存在了。
四. IDENTITY函数
这是一个函数,使用时和IDENTITY属性的格式很相似,不过两者没什么关系,纯粹因为名字相同,顺便提一下。
select IDENTITY(int,1,1) as id into #t from sysobjects select cast(IDENTITY(int,1,1) as varchar(1000)) as id into #t2 from sysobjects -- can not use expression with identity function directly
IDENTITY函数限制比较多,只能用在SELECT INTO语句里,不能结合表达式使用,而且有了ROW_NUMBER(),IDENTITY函数就更显得不好用了。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

CrystalDiskMark是一款適用於硬碟的小型HDD基準測試工具,可快速測量順序和隨機讀取/寫入速度。接下來就讓小編為大家介紹一下CrystalDiskMark,以及crystaldiskmark如何使用吧~一、CrystalDiskMark介紹CrystalDiskMark是一款廣泛使用的磁碟效能測試工具,用於評估機械硬碟和固態硬碟(SSD)的讀取和寫入速度和隨機I/O性能。它是一款免費的Windows應用程序,並提供用戶友好的介面和各種測試模式來評估硬碟效能的不同方面,並被廣泛用於硬體評

foobar2000是一款能隨時收聽音樂資源的軟體,各種音樂無損音質帶給你,增強版本的音樂播放器,讓你得到更全更舒適的音樂體驗,它的設計理念是將電腦端的高級音頻播放器移植到手機上,提供更便捷高效的音樂播放體驗,介面設計簡潔明了易於使用它採用了極簡的設計風格,沒有過多的裝飾和繁瑣的操作能夠快速上手,同時還支持多種皮膚和主題,根據自己的喜好進行個性化設置,打造專屬的音樂播放器支援多種音訊格式的播放,它還支援音訊增益功能根據自己的聽力情況調整音量大小,避免過大的音量對聽力造成損害。接下來就讓小編為大

這個AI輔助程式工具在這個AI快速發展的階段,挖掘出了一大批好用的AI輔助程式工具。 AI輔助程式設計工具能夠提升開發效率、提升程式碼品質、降低bug率,是現代軟體開發過程中的重要助手。今天大姚給大家分享4款AI輔助程式工具(而且都支援C#語言),希望對大家有幫助。 https://github.com/YSGStudyHards/DotNetGuide1.GitHubCopilotGitHubCopilot是一款AI編碼助手,可幫助你更快、更省力地編寫程式碼,從而將更多精力集中在問題解決和協作上。 Git

在如今雲端儲存已成為我們日常生活和工作中不可或缺的一部分。百度網盤作為國內領先的雲端儲存服務之一,憑藉其強大的儲存功能、高效的傳輸速度以及便捷的操作體驗,贏得了廣大用戶的青睞。而且無論你是想要備份重要文件、分享資料,還是在線上觀看影片、聽取音樂,百度網盤都能滿足你的需求。但很多用戶可能對百度網盤app的具體使用方法還不了解,那麼這篇教學就將為大家詳細介紹百度網盤app如何使用,還有疑惑的用戶們就快來跟著本文詳細了解一下吧!百度雲網盤怎麼用:一、安裝首先,下載並安裝百度雲軟體時,請選擇自訂安裝選

網易郵箱,作為中國網友廣泛使用的一種電子郵箱,一直以來以其穩定、高效的服務贏得了用戶的信賴。而網易信箱大師,則是專為手機使用者打造的信箱軟體,它大大簡化了郵件的收發流程,讓我們的郵件處理變得更加便利。那麼網易信箱大師該如何使用,具體又有哪些功能呢,下文中本站小編將為大家帶來詳細的內容介紹,希望能幫助到大家!首先,您可以在手機應用程式商店搜尋並下載網易信箱大師應用程式。在應用寶或百度手機助手中搜尋“網易郵箱大師”,然後按照提示進行安裝即可。下載安裝完成後,我們打開網易郵箱帳號並進行登錄,登入介面如下圖所示

MetaMask(中文也叫小狐狸錢包)是一款免費的、廣受好評的加密錢包軟體。目前,BTCC已支援綁定MetaMask錢包,綁定後可使用MetaMask錢包進行快速登錄,儲值、買幣等,且首次綁定還可獲得20USDT體驗金。在BTCCMetaMask錢包教學中,我們將詳細介紹如何註冊和使用MetaMask,以及如何在BTCC綁定並使用小狐狸錢包。 MetaMask錢包是什麼? MetaMask小狐狸錢包擁有超過3,000萬用戶,是當今最受歡迎的加密貨幣錢包之一。它可免費使用,可作為擴充功能安裝在網絡

Apple在周二推出了iOS17.4更新,為iPhone帶來了一系列新功能和修復。這次更新包含了全新的表情符號,同時歐盟用戶也能夠下載其他應用程式商店。此外,更新還加強了對iPhone安全性的控制,引入了更多的「失竊設備保護」設定選項,為用戶提供更多選擇和保障。 "iOS17.3首次引入了「失竊設備保護」功能,為用戶的敏感資料增加了額外的安全保障。當用戶不在家等熟悉地點時,該功能要求用戶首次輸入生物特徵信息,並在一小時後再次輸入資訊才能存取和更改某些數據,如修改AppleID密碼或關閉失竊設備保護功能

2022年3月3日,距離世界首個AI程式設計師Devin誕生不足一個月,普林斯頓大學的NLP團隊開發了一個開源AI程式設計師SWE-agent。它利用GPT-4模型在GitHub儲存庫中自動解決問題。 SWE-agent在SWE-bench測試集上的表現與Devin相似,平均耗時93秒,解決了12.29%的問題。 SWE-agent透過與專用終端交互,可以開啟、搜尋文件內容,使用自動語法檢查、編輯特定行,以及編寫和執行測試。 (註:以上內容為原始內容微調,但保留了原文中的關鍵訊息,未超過指定字數限制。)SWE-A
