在SQL Server 2005中即时查找主键约束

6

我有以下SQL语句:

 ALTER TABLE dbo.PS_userVariables DROP CONSTRAINT PK_PS_userVariables;
 ALTER TABLE dbo.PS_userVariables ADD PRIMARY KEY (varnumber, subjectID, userID, datasetID, listid, userVarTitle);

由于我有多个环境,因此在我的不同数据库上,PK_PS_userVariables约束名称是不同的。我该如何编写一个脚本来获取该名称,然后将其添加到我的脚本中?


您想删除所有约束条件,还是仅特定的一个? - OMG Ponies
我想在那张表上删除所有主键,然后添加我的额外主键。 - cdub
请生成所有的约束脚本,可参考以下链接:https://dev59.com/Nm025IYBdhLWcg3wRDq8,或者搜索该链接:http://stackoverflow.com/search?q=[sql-server]+drop+constraints - OMG Ponies
1
一张表格只能有一个主键,这就是为什么它被称为主键的原因。 :-) - Aaron Bertrand
@aaron,您说只能有一个主键是什么意思?您指的是列还是指主键意味着数据规范化? - cdub
我想说的是,你只能向表中添加一个PRIMARY KEY约束(无论有多少列),因此“该表上的所有主键”与“该表上的主键”相同。 - Aaron Bertrand
4个回答

17

虽然典型的最佳实践是始终明确地命名约束条件,但您可以从目录视图动态获取它们:

DECLARE @table NVARCHAR(512), @sql NVARCHAR(MAX);

SELECT @table = N'dbo.PS_userVariables';

SELECT @sql = 'ALTER TABLE ' + @table 
    + ' DROP CONSTRAINT ' + name + ';'
    FROM sys.key_constraints
    WHERE [type] = 'PK'
    AND [parent_object_id] = OBJECT_ID(@table);

EXEC sp_executeSQL @sql;

ALTER TABLE dbo.PS_userVariables ADD CONSTRAINT ...

3
SELECT 
   A.TABLE_NAME, 
   A.CONSTRAINT_NAME, 
   B.COLUMN_NAME
FROM 
   INFORMATION_SCHEMA.TABLE_CONSTRAINTS A, 
   INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE B
WHERE 
      CONSTRAINT_TYPE = 'PRIMARY KEY' 
   AND A.CONSTRAINT_NAME = B.CONSTRAINT_NAME
ORDER BY 
   A.TABLE_NAME 

参考: Pinal Dave @ http://blog.sqlauthority.com/2008/09/06/sql-server-find-primary-key-using-sql-server-management-studio/

这篇文章介绍了如何使用SQL Server Management Studio查找主键。首先,打开对象资源管理器并展开数据库,然后展开表格。在表格下面有一个名为“键”的文件夹,展开它可以看到所有的键,包括主键。双击主键即可查看主键详细信息。

1
除非您需要严格遵守和适应跨平台,否则我建议不要使用INFORMATION_SCHEMA视图。在这种情况下可能还可以,但在很多情况下,由于I_S视图没有得到维护,它们缺少您需要去目录视图获取的关键信息(例如索引-包括列、过滤器等在INFORMATION_SCHEMA中无法找到)。 - Aaron Bertrand
不是在争论语义学——易用并不与一致相矛盾。一致性是好的,但这是支持信息模式的论点,而不是反对它。系统视图会随着服务器的新版本而重新定义,这就是我所说的可扩展性——今天编写的信息模式依赖项应该在下一个版本中仍然有效。另一方面,系统视图依赖项需要进行双重检查。无论如何,你的方法和我的方法都行得通,我认为它们都很好,但并不是一个比另一个更好——这取决于手头的工作。 - Chains
不确定在仅涉及SQL Server的情况下,一致性如何成为支持INFORMATION_SCHEMA的论点(大多数人不会在一天内跳转到不同的RDBMS平台,大多数公司也不会在一夜之间迁移到不同的平台)。当我说一致性时,我是指在主键方面使用INFORMATION_SCHEMA,而在索引方面使用sys.indexes等。 - Aaron Bertrand
我想我会使用任何我需要的东西。我同时使用系统视图和信息模式(以及其他元数据视图,不仅仅是这两个)。你是说你永远不会使用信息模式,而只是始终使用系统视图,无论如何?不确定在这里保持一致性的价值是什么,但好吧——我相信那对你来说会起作用。你认为微软为什么会推出信息模式呢?也许是因为它预见并提供了最常见的需求,并朝着这个方向努力,他们想让事情变得……等等……更容易? :-) 只是和你开玩笑。无论如何,你已经赢得了这个问题。 :-P - Chains
微软推出了 INFORMATION_SCHEMA,因为它是标准的一部分。不幸的是,由于他们添加了一些不适合标准视图的欢迎功能,目录视图对于任何正在开发功能的对象(如索引)更有意义。虽然我可以列举出许多从目录视图中获取的信息,但我不知道有任何数据可以从 INFORMATION_SCHEMA 视图中获取,而无法从目录视图中获取。你能说出来吗? - Aaron Bertrand
显示剩余4条评论

1
DECLARE @TableName varchar(128)
DECLARE @IndexName varchar(128)
DECLARE @Command varchar(1000)

SET @TableName = 'PS_userVariables'

SELECT @IndexName = si.name
FROM sys.tables st
JOIN sys.indexes si ON st.object_id = si.object_id
WHERE st.name = @TableName
  AND si.is_primary_key = 1

SET @Command = 'ALTER TABLE dbo.' + QUOTENAME(@Tablename) + ' DROP CONSTRAINT ' + QUOTENAME(@IndexName) + ';
ALTER TABLE dbo.' + QUOTENAME(@Tablename) + ' ADD PRIMARY KEY (varnumber, subjectID, userID, datasetID, listid, userVarTitle);'

0

我的使用案例是更新由Entity Framework 6生成的主键约束名称,以匹配Entity Framework Core的主键命名约定。

由于EF使用迁移,我创建了一个UpDown迁移脚本,并创建了一个临时的长期存储表来存储旧的和新的约束名称,以便在需要时可以回滚。

这是我用来更新主键约束名称的SQL:

-- create a temporary long-lived table
-- it can be deleted when rollback is no longer needed
CREATE TABLE dbo.__OldPrimaryKeyConstraintNames (
  SchemaName NVARCHAR(128) NOT NULL DEFAULT 'dbo',
  TableName NVARCHAR(128) NOT NULL,
  OldPrimaryKeyConstraintName NVARCHAR(128) NOT NULL,
  NewPrimaryKeyConstraintName NVARCHAR(128) NOT NULL
);

-- create a temporary table to hold the data for the script
DECLARE @tbl TABLE (SchemaName NVARCHAR(3), TableName NVARCHAR(128), PrimaryKeyConstraintName NVARCHAR(128));

-- get all primary key constraint names as well as it's schema and table
INSERT INTO @tbl
SELECT SCHEMA_NAME(pk.schema_id), t.name, pk.name
FROM sys.key_constraints pk
INNER JOIN sys.objects t on t.object_id = pk.parent_object_id
WHERE  pk.type = 'PK'

-- row count used for iterating through @tbl
DECLARE @RowCount INT = (SELECT COUNT(*) FROM @tbl);

-- variables used when used for iterating through @tbl
DECLARE @SchemaName NVARCHAR(128)
DECLARE @TableName NVARCHAR(128)
DECLARE @OldPrimaryKeyConstraintName NVARCHAR(128)
DECLARE @NewPrimaryKeyConstraintName NVARCHAR(128)
DECLARE @RenameSql NVARCHAR(MAX)

WHILE @RowCount > 0 BEGIN
  -- get the primary key constraint name, schema, and table name for this iteration
  SELECT @SchemaName = SchemaName, @TableName = TableName, @OldPrimaryKeyConstraintName = PrimaryKeyConstraintName, @NewPrimaryKeyConstraintName = CONCAT('PK_', TableName)
  FROM @tbl
  ORDER BY PrimaryKeyConstraintName DESC OFFSET @RowCount - 1 ROWS FETCH NEXT 1 ROWS ONLY;

  -- store the old and new primary key constraint names
  INSERT __OldPrimaryKeyConstraintNames (SchemaName, TableName, OldPrimaryKeyConstraintName, NewPrimaryKeyConstraintName)
  VALUES (@SchemaName, @TableName, @OldPrimaryKeyConstraintName, @NewPrimaryKeyConstraintName)

  -- perform the rename
  SET @RenameSql = 'sp_rename ' + '''' + @SchemaName + '.' + QUOTENAME(@OldPrimaryKeyConstraintName) + '''' + ', ' + '''' + @NewPrimaryKeyConstraintName + ''''
  EXEC sp_executeSQL @RenameSql

  -- move to the next row
  SET @RowCount -= 1;
END

运行此脚本后,dbo.__OldPrimaryKeyConstraintNames应该包含旧的和新的约束名称。
这样我们就可以在需要时恢复重命名操作。
以下是我用于恢复主键约束名称的SQL:
-- create a temporary table to hold the data for the script
DECLARE @tbl TABLE (SchemaName NVARCHAR(3), OldPrimaryKeyConstraintName NVARCHAR(128), NewPrimaryKeyConstraintName NVARCHAR(128));

-- get the old and new constraint names as well as it's schema and table name 
INSERT INTO @tbl
SELECT SchemaName, OldPrimaryKeyConstraintName, NewPrimaryKeyConstraintName
FROM dbo.__OldPrimaryKeyConstraintNames

-- row count used for iterating through @tbl
DECLARE @RowCount INT = (SELECT COUNT(*) FROM @tbl);

-- variables used when used for iterating through @tbl
DECLARE @SchemaName NVARCHAR(128)
DECLARE @TableName NVARCHAR(128)
DECLARE @OldPrimaryKeyConstraintName NVARCHAR(128)
DECLARE @NewPrimaryKeyConstraintName NVARCHAR(128)
DECLARE @RenameSql NVARCHAR(MAX)

WHILE @RowCount > 0 BEGIN
  -- get the old and new constraint name and it's schema for this iteration
  SELECT @SchemaName = SchemaName, @OldPrimaryKeyConstraintName = OldPrimaryKeyConstraintName, @NewPrimaryKeyConstraintName = NewPrimaryKeyConstraintName
  FROM @tbl
  ORDER BY OldPrimaryKeyConstraintName DESC OFFSET @RowCount - 1 ROWS FETCH NEXT 1 ROWS ONLY;

  -- revert the rename
  SET @RenameSql = 'sp_rename ' + '''' + @SchemaName + '.' + QUOTENAME(@NewPrimaryKeyConstraintName) + '''' + ', ' + '''' + @OldPrimaryKeyConstraintName + ''''
  SELECT @RenameSql
  EXEC sp_executeSQL @RenameSql

  -- move to the next row
  SET @RowCount -= 1;
END

-- drop the temporary long-lived table as it is not required 
DROP TABLE IF EXISTS dbo.__OldPrimaryKeyConstraintNames

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接