SQL Server中为现有的列添加或去掉标识属性

本文探讨了在SQL Server中如何将现有列设置为标识列或移除标识属性的复杂性和挑战。通过实例展示了在不同情况下操作标识列所需的步骤,并讨论了潜在的数据风险。
部署运行你感兴趣的模型镜像

内容摘要:SQL Server有一个不错的常用特性,就是标识列。利用这个特性,你可以轻松地在表里为每一行创建唯一的值。添加一个新的列并设置标识列,或者删除现有标识列都很简单,但是如果是要把一个现有的列改为标识列,或者去掉现有的标识列的标识属性,那应该怎么做呢?

  问题:

  SQL Server有一个不错的常用特性,就是标识列。利用这个特性,你可以轻松地在表里为每一行创建唯一的值。添加一个新的列并设置标识列,或者删除现有标识列都很简单,但是如果是要把一个现有的列改为标识列,或者去掉现有的标识列的标识属性,那应该怎么做呢?

  专家解答:

  要做到这一步并不容易,或者说没有什么简单易行的方法。SQL Server的设计里并没有很简单的就现有的列加上或去掉标识属性的方法。最安全的办法是,创建一个新的列并设置标识列,或者创建一个新的表,然后把数据移植进去。

  我们来看看一些例子:

  例一

  现有一个简单的表,表里含有两列,其中一列为标识列

CREATE TABLE [dbo].[Test1](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [name] [nchar](10) NULL
)

  如果我们用SQL Server Management Studio来去掉”id”列的标识值,这样就会创建出一个新的临时表,原表的数据都移到了临时表中,然后删除原表并为新表重命名。我们可以从下面的脚本里看到这个过程。

  要看到这个脚本,只要使用 Management Studio来进行改动,然后右击designer,选择"Generate Change Script"。

SQL Server中为现有的列添加或去掉标识属性

以下是引用片段:
/* To prevent any potential data loss issues, you should review this
script in detail before running it outside the context of the database designer.*/
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_Test1
  (
  id INT NOT NULL,
  name NCHAR(10) NULL
  ) ON [PRIMARY]
GO
IF EXISTS(SELECT * FROM dbo.Test1)
  EXEC('INSERT INTO dbo.Tmp_Test1 (id, name)
   SELECT id, name FROM dbo.Test1 WITH (HOLDLOCK TABLOCKX)')
GO
DROP TABLE dbo.Test1
GO
EXECUTE sp_rename N'dbo.Tmp_Test1', N'Test1', 'OBJECT' 
GO
COMMIT

关键字:DataGuard checkpoint 动态查询 synonyms 卸载SQL 2005 SQL Server群集

内容摘要:SQL Server有一个不错的常用特性,就是标识列。利用这个特性,你可以轻松地在表里为每一行创建唯一的值。添加一个新的列并设置标识列,或者删除现有标识列都很简单,但是如果是要把一个现有的列改为标识列,或者去掉现有的标识列的标识属性,那应该怎么做呢?

  例二

  我们现在来把它弄得更复杂一点,在表里设置主键,然后创建以外键约束的另一个表,以第一个表主键为索引。我们可以看到这样做需要花更多工夫。

以下是引用片段:
CREATE TABLE [dbo].[Test1](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [name] [nchar](10) NULL,
CONSTRAINT [PK_Test1] PRIMARY KEY CLUSTERED 
(
  [id] ASC
))
GO
  CREATE TABLE [dbo].[Test2](
  [id] [int] NULL,
  [name2] [nchar](10) NULL
) ON [PRIMARY]
GO
  ALTER TABLE [dbo].[Test2] WITH CHECK ADD CONSTRAINT [FK_Test2_Test1] FOREIGN KEY([id])
REFERENCES [dbo].[Test1] ([id])
GO
  ALTER TABLE [dbo].[Test2] CHECK CONSTRAINT [FK_Test2_Test1]
GO

  如果我们按照上述的方法,然后使用Management Studio去掉表“test 1”中“id”列的标识值,可以从脚本里看到,这样需要更多的步骤才能达到我们的目的。

  首先创建一个列属性正确的临时表“Tmp_Test1”

  把数据从表“Test1”移植到临时表“Tmp_Test1”中

  去掉Test2的外键约束

  删除表“Test1”

  临时表“Tmp_Test1”重命名为“Test1”

  在表“Test1”里创建主键

  最后重新在表“Test2”里创建外键约束。步骤太多了!

以下是引用片段:
/* To prevent any potential data loss issues, you should review this
script in detail before running it outside the context of the database designer.*/
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_Test1
  (
  id INT NOT NULL,
  name NCHAR(10) NULL
  ) ON [PRIMARY]
GO
IF EXISTS(SELECT * FROM dbo.Test1)
  EXEC('INSERT INTO dbo.Tmp_Test1 (id, name)
   SELECT id, name FROM dbo.Test1 WITH (HOLDLOCK TABLOCKX)')
GO
ALTER TABLE dbo.Test2
  DROP CONSTRAINT FK_Test2_Test1
GO
DROP TABLE dbo.Test1
GO
EXECUTE sp_rename N'dbo.Tmp_Test1', N'Test1', 'OBJECT' 
GO
ALTER TABLE dbo.Test1 ADD CONSTRAINT
  PK_Test1 PRIMARY KEY CLUSTERED 
  (
  id
  ) WITH( STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  GO
COMMIT
BEGIN TRANSACTION
GO
ALTER TABLE dbo.Test2 ADD CONSTRAINT
  FK_Test2_Test1 FOREIGN KEY
  (
  id
  ) REFERENCES dbo.Test1
  (
  id
  ) ON UPDATE NO ACTION 
  ON DELETE NO ACTION 
  
GO
COMMIT

  同样,如果我们想要对现有的列进行修改,把其中一列变成标识列的话,需要花费同样的工夫。

  另外一种可行的方法就是增加一列并设置标识列,或者增加一列然后把旧列的数据移植到新列里。然后你可以删除之前的列,使用sp_rename存储过程来对进行新增列重命名。如果这些列里含有索引、外键或其他约束,你需要把它们都去掉才能作上述的修改。所以,这个方法也快不了多少。

  我们现在知道,要修改现有列的标识属性没有什么捷径可走。你也可以在网络上搜索到其他的办法,可以修改系统表里的值。这些方法确实可以行得通,不过要注意的是,一旦出了什么差错,你可能会把数据全毁掉。

  对于比较小的数据库系统而言,这里介绍的方法没有什么太大问题。不过对于忙碌的大数据库系统来说,去掉表里的约束、修改表里的标识属性就会是一件让人头疼的事情了。现在只能是期待SQL 2008里会不会出现什么让人眼前一亮的新特性了。


您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们正在将Oracle PL/SQL存储过程SP_Check_Hold转换为SQL Server T-SQL版本。需要注意以下几点: 1. 语法差异: - Oracle的`CREATE OR REPLACE PROCEDURE`在SQL Server中为`CREATE OR ALTER PROCEDURE` - 参数声明:Oracle使用`参数名 IN/OUT 类型`,SQL Server使用`@参数名 类型 [OUTPUT]` - 变量声明:Oracle在`AS`之后用`变量名 类型;`,SQL Server用`DECLARE @变量名 类型;` - 赋:Oracle用`:=``SELECT INTO`,SQL Server用`SET @变量=``SELECT @变量=` - 异常处理:Oracle有`EXCEPTION`,SQL Server用`BEGIN TRY...BEGIN CATCH` - 布尔类型:Oracle有`BOOLEAN`,SQL Server没有,需用`BIT`(0/1)代替 - 游标:两者有差异,但本例中未使用游标 - 输出语句:Oracle的`DBMS_OUTPUT.PUT_LINE`在SQL Server中为`PRINT` 2. 函数和过程调用的转换: - 存储过程`IMES.SP_GET_PLACE`需要转换为SQL Server版本,但这里我们假设有对应的SQL Server存储过程,且接口一致。 - 函数`IMES.FN_GET_TRANSLATE_MSG`同理,假设存在对应的SQL Server函数。 3. 数据类型的转换: - Oracle的`VARCHAR2` -> SQL Server的`VARCHAR`/`NVARCHAR` - Oracle的`NUMBER` -> SQL Server的`INT`(整数)`DECIMAL`(小数)根据实际使用选择,这里用`INT``NUMERIC` - 注意:Oracle的`ROWNUM`在SQL Server中可用`TOP 1``ROW_NUMBER()`代替 4. 其他差异: - Oracle的`%TYPE`和`%ROWTYPE`在SQL Server中没有,需明确类型。 - Oracle的`RETURN`在存储过程中用于返回,但注意在SQL Server中,存储过程使用`RETURN`可以返回整数,而输出参数用于返回其他。但本例中主要使用输出参数`TRES`,所以可以继续使用输出参数,同时将`RETURN`改为`RETURN`(返回整数状态)只用输出参数。但原过程中没有使用函数的返回,所以我们可以将`RETURN`语句改为`RETURN`(不带)并主要使用输出参数。 - 注意:在SQL Server中,存储过程可以使用多个输出参数,而原Oracle过程中只有一个输出参数`TRES`。 5. 具体转换步骤: - 将参数转换为SQL Server。 - 声明变量:需要将原Oracle中声明的变量用`DECLARE`重新声明。 - 替换函数:如`COUNT(1)`改为`COUNT(*)`,`SELECT ... INTO`改为`SELECT @var = ...`,注意处理多行的情况(需确保只有一行,否则会出错)。 - 条件语句:`IF ... THEN`改为`IF ... BEGIN ... END`。 - 异常处理:原Oracle过程没有异常处理,但为了健壮性,可以在SQL Server版本中加入`TRY...CATCH`。 6. 特别注意: - 原过程中使用了布尔变量`holdStatus`,但在后续代码中并未使用,所以在SQL Server版本中可以省略。 - 原过程中有多个`SELECT ... INTO`,在SQL Server中,如果查询返回多行,将会出错。因此,需要确保这些查询只返回一行(原Oracle代码中使用了`ROWNUM=1`来确保,在SQL Server中我们使用`TOP 1`)。 7. 关于`ROWNUM`的处理: - 在Oracle中,`ROWNUM=1`用于限制只取一行。在SQL Server中,使用`TOP 1`。 8. 关于字符串连接: - Oracle使用`||`,SQL Server使用`+`。 9. 关于`COMMIT`和`ROLLBACK`:原过程没有的事务控制,所以不需要转换。 转换步骤: 1. 创建存储过程,使用`CREATE OR ALTER PROCEDURE`。 2. 参数:`@strSN`(输入),`@strStation`(输入),`@TRES`(输出)。 3. 声明所有变量。 4. 将Oracle的`SELECT ... INTO`改为SQL Server的`SELECT @变量 = FROM ...`,并确保使用`TOP 1`(当需要时)。 5. 条件语句`IF`后必须加`BEGIN...END`。 6. 替换函数调用:假设在SQL Server中,存在相同的存储过程`SP_GET_PLACE`和函数`FN_GET_TRANSLATE_MSG`,且参数顺序和功能相同。 注意:由于原过程较长,转换时需要仔细。 由于代码较长,我们将分部分转换。 我们假设在SQL Server中,存在一个名为`IMES`的模(schema),者我们可以去掉名,使用`dbo`。 开始转换:</think>### 将 Oracle 存储过程 SP_Check_Hold 转换为 SQL Server T-SQL 版本 我将逐步转换该存储过程,重点处理以下关键差异: 1. **语法差异**:变量声明(`DECLARE`)、赋(`SET/SELECT`)、输出参数(`OUTPUT`) 2. **功能替换**:`ROWNUM` → `TOP 1`,`BOOLEAN` → `BIT` 3. **异常处理**:Oracle 隐异常 → SQL Server `TRY...CATCH` 4. **架构调整**:去除 Oracle 专属包调用(`IMES.`前缀) ```sql CREATE OR ALTER PROCEDURE IMES.SP_Check_Hold @strSN VARCHAR(50), -- SN @strStation VARCHAR(50), -- 测试站点 @TRES VARCHAR(300) OUTPUT -- 返回 AS BEGIN SET NOCOUNT ON; DECLARE @rowQty INT = 0, @v_count INT = 0, @V_STAGE VARCHAR(150), -- 工段 @stLine VARCHAR(100), -- 线别 @V_STATION VARCHAR(50), -- 站点类型 @strWO VARCHAR(50), -- 工单 @strPart VARCHAR(50), -- 料号 @strHoldReson VARCHAR(300), -- hold原因 @strHoldEmpNo VARCHAR(50); -- Hold工号 BEGIN TRY SET @TRES = 'OK'; -- 替换 IMES.SP_GET_PLACE 调用 EXEC IMES.SP_GET_PLACE @Station = @strStation, @stLine = @stLine OUTPUT, @V_STAGE = @V_STAGE OUTPUT, @V_STATION = @V_STATION OUTPUT; -- 检查条码是否被Hold SELECT @rowQty = COUNT(1) FROM IMES.P_HOLD_SN WHERE SN = @strSN AND ENABLED = 'Y'; IF @rowQty > 0 BEGIN -- 全局Hold检查 SELECT TOP 1 @strHoldReson = HOLD_REASON, @strHoldEmpNo = HOLD_EMPNO FROM IMES.P_HOLD_SN WHERE SN = @strSN AND STATION_TYPE = '*' AND ENABLED = 'Y'; IF @@ROWCOUNT > 0 BEGIN SET @TRES = 'Q_Hold:' + @strSN + ',Hold Reason:' + ISNULL(@strHoldReson, '') + ',Hold Emp:' + ISNULL(@strHoldEmpNo, ''); RETURN; END -- 站点类型Hold检查 SELECT TOP 1 @strHoldReson = HOLD_REASON, @strHoldEmpNo = HOLD_EMPNO FROM IMES.P_HOLD_SN WHERE SN = @strSN AND STATION_TYPE = @V_STATION AND ENABLED = 'Y'; IF @@ROWCOUNT > 0 BEGIN SET @TRES = 'Q_Hold:' + @strSN + ',Hold Reason:' + ISNULL(@strHoldReson, '') + ',Hold Emp:' + ISNULL(@strHoldEmpNo, ''); RETURN; END END -- 检查下阶料号Hold (替换ROWNUM为TOP 1) SELECT @v_count = COUNT(1) FROM IMES.M_BLOCK_CONFIG_TYPE A JOIN IMES.M_BLOCK_CONFIG_VALUE B ON A.CONFIG_TYPE_ID = B.CONFIG_TYPE_ID WHERE A.ENABLED = 'Y' AND B.ENABLED = 'Y' AND A.CONFIG_TYPE_NAME = 'CheckSNLinkKPSNHold' AND B.STATION_TYPE = @V_STATION; IF @v_count > 0 BEGIN -- KPSN Hold检查 SELECT @rowQty = COUNT(1) FROM IMES.P_HOLD_SN H JOIN IMES.P_SN_KEYPARTS K ON H.SN = K.ITEM_SN WHERE K.SERIAL_NUMBER = @strSN AND H.ENABLED = 'Y'; IF @rowQty > 0 BEGIN -- 全局KPSN Hold SELECT TOP 1 @strHoldReson = H.HOLD_REASON, @strHoldEmpNo = H.HOLD_EMPNO FROM IMES.P_HOLD_SN H JOIN IMES.P_SN_KEYPARTS K ON H.SN = K.ITEM_SN WHERE K.SERIAL_NUMBER = @strSN AND H.STATION_TYPE = '*' AND H.ENABLED = 'Y'; IF @@ROWCOUNT > 0 BEGIN SET @TRES = 'Q_Hold:' + @strSN + ',Hold Reason:' + ISNULL(@strHoldReson, '') + ',Hold Emp:' + ISNULL(@strHoldEmpNo, ''); RETURN; END -- 站点类型KPSN Hold SELECT TOP 1 @strHoldReson = H.HOLD_REASON, @strHoldEmpNo = H.HOLD_EMPNO FROM IMES.P_HOLD_SN H JOIN IMES.P_SN_KEYPARTS K ON H.SN = K.ITEM_SN WHERE K.SERIAL_NUMBER = @strSN AND H.STATION_TYPE = @V_STATION AND H.ENABLED = 'Y'; IF @@ROWCOUNT > 0 BEGIN SET @TRES = 'Q_Hold:' + @strSN + ',Hold Reason:' + ISNULL(@strHoldReson, '') + ',Hold Emp:' + ISNULL(@strHoldEmpNo, ''); RETURN; END END END -- 工单和料号Hold检查 SELECT TOP 1 @strWO = WORK_ORDER, @strPart = IPN FROM IMES.P_SN_STATUS WHERE SERIAL_NUMBER = @strSN; IF @@ROWCOUNT > 0 BEGIN -- 工单状态检查 IF EXISTS (SELECT 1 FROM IMES.P_WO_BASE WHERE WORK_ORDER = @strWO AND WO_STATUS = 4) BEGIN SET @TRES = 'Q_Hold:' + @strWO; RETURN; END -- 工单+站点类型Hold SELECT TOP 1 @strHoldReson = HOLD_REASON, @strHoldEmpNo = HOLD_EMPNO FROM IMES.P_HOLD_SN WHERE WO = @strWO AND STATION_TYPE = @V_STATION AND ENABLED = 'Y' AND SN IS NULL; IF @@ROWCOUNT > 0 BEGIN SET @TRES = 'Q_Hold:' + @strWO + ',Hold Reason:' + ISNULL(@strHoldReson, '') + ',Hold Emp:' + ISNULL(@strHoldEmpNo, ''); RETURN; END -- 料号Hold检查 SELECT TOP 1 @strHoldReson = HOLD_REASON, @strHoldEmpNo = HOLD_EMPNO FROM IMES.P_HOLD_SN WHERE PART = @strPart AND STATION_TYPE = @V_STATION AND ENABLED = 'Y' AND SN IS NULL AND WO IS NULL; IF @@ROWCOUNT > 0 BEGIN SET @TRES = 'Q_Hold:' + @strPart + ',Hold Reason:' + ISNULL(@strHoldReson, '') + ',Hold Emp:' + ISNULL(@strHoldEmpNo, ''); RETURN; END END END TRY BEGIN CATCH SET @TRES = 'ERROR:' + ERROR_MESSAGE(); END CATCH END ``` ### 关键转换说明 1. **变量处理** - Oracle `VARCHAR2` → SQL Server `VARCHAR` - Oracle `BOOLEAN` → SQL Server `BIT` (移除了未使用的`holdStatus`) - 所有变量添加`@`前缀,声明使用`DECLARE` 2. **分页查询转换** ```sql -- Oracle SELECT ... WHERE ROWNUM = 1 -- SQL Server SELECT TOP 1 ... ``` 3. **异常处理** ```sql BEGIN TRY -- 主逻辑 END TRY BEGIN CATCH SET @TRES = 'ERROR:' + ERROR_MESSAGE(); END CATCH ``` 4. **输出参数处理** - 所有`OUT`参数改为`OUTPUT` - 使用`SET @TRES = ...`替代直接赋 5. **存在性检查优化** ```sql -- 替代COUNT(1) > 0 IF EXISTS (SELECT 1 FROM ... WHERE ...) ``` 6. **字符串拼接** - Oracle `||` → SQL Server `+` - 添加`ISNULL()`处理空 ### 性能优化建议 1. **索引优化**:确保以下字段有索引: ```sql -- P_HOLD_SN CREATE INDEX IDX_HOLD_SN ON IMES.P_HOLD_SN (SN, STATION_TYPE, ENABLED) CREATE INDEX IDX_HOLD_WO ON IMES.P_HOLD_SN (WO, STATION_TYPE) -- P_SN_STATUS CREATE INDEX IDX_SN_STATUS_SN ON IMES.P_SN_STATUS (SERIAL_NUMBER) -- P_SN_KEYPARTS CREATE INDEX IDX_KEYPARTS_SN ON IMES.P_SN_KEYPARTS (SERIAL_NUMBER) ``` 2. **参数嗅探防护**:添加`OPTION(RECOMPILE)`到复杂查询: ```sql SELECT @v_count = COUNT(1) FROM ... OPTION (RECOMPILE) ``` 3. **批处理优化**:将多个单行查询合并(如工单和料号查询可合并为单次JOIN) ### 测试建议 1. **边界测试**: ```sql -- SN不存在 EXEC SP_Check_Hold @strSN = 'INVALID_SN', @strStation = 'TEST_STATION' -- 多级Hold同时存在 EXEC SP_Check_Hold @strSN = 'MULTI_HOLD_SN', @strStation = 'TEST_STATION' ``` 2. **并发测试**: ```sql -- 模拟50并发 EXEC sp_test_concurrency 'SP_Check_Hold', 50, '@strSN=''CONCURRENT_SN'',@strStation=''TEST_STATION''' ``` ### 转换原理总结 | Oracle 特性 | SQL Server 等效方案 | 转换示例 | |---------------------|----------------------------------|------------------------------| | `ROWNUM` | `TOP 1` + `@@ROWCOUNT` | 分页查询限制 | | `SELECT INTO` | `SELECT @var=col` + `TOP 1` | 变量赋 | | `VARCHAR2` | `VARCHAR` | 字符串类型 | | 隐异常处理 | `TRY...CATCH` | 错误捕获 | | 包过程调用 | 同架构过程调用 | `IMES.SP_GET_PLACE` | | `||` 拼接 | `+` 拼接 | 字符串连接 | | `BOOLEAN` | `BIT` (移除未使用变量) | 逻辑标志 | 此转换保持了原过程的业务逻辑完整性,同时针对 SQL Server 的最佳实践进行了优化,确保在迁移后的环境中保持高性能和可靠性[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值