Как отключить ограничение первичного ключа программно?

У меня есть таблица с первичным ключом в моей таблице MS SQL Server 2005. Я хотел бы отключить его. Теперь я получаю ошибку:

нарушение ограничения первичного ключа "PK_Name". Не удается вставить повторяющийся ключ в объект 'dbo.Стол".

Я хотел бы, чтобы эта ошибка не возникала и работала с первичным ключом, как с обычным столбцом без ограничений, и восстанавливала это ограничение после внесения в него изменений. Как отключить это ограничение?

запрос, который я хочу выполнить в то время как ограничение первичного ключа отключено, является сложным и изменяет значения в столбце первичного ключа. В некоторых точках этого запроса возникает ситуация, когда у меня есть повторяющиеся значения в столбце первичного ключа. Но в конце моего запроса, у меня все значения уникальные.

Я мало знаю об этом ограничении, потому что я не дизайнер этой таблицы. У меня есть его имя, но я не сейчас, если он кластеризован и так далее (Что такое конфигурация этого столбца).

6 ответов


реляционные таблицы без первичных ключей-очень плохая вещь. Каждая строка должна быть уникальной. Если ни один из ключей-кандидатов не обозначен как первичный, вся строка должна быть уникальной.

Я не уверен, почему вы должны отказаться от ограничения первичного ключа, но я бы рассмотрел возможность сделать это, не заменяя его одним из других ключей-кандидатов, это красный флаг, который следует исследовать.


ALTER TABLE mytable DROP CONSTRAINT PK_Name

, чтобы включить его:

ALTER TABLE mytable ADD CONSTRAINT PK_Name PRIMARY KEY /* CLUSTERED */ (pk_column)

раскомментировать CLUSTERED Если вы хотите PRIMARY KEY быть кластеризованным (i. e. сами строки таблицы упорядочиваются)

чтобы выяснить, если PRIMARY KEY группируется по не, вопрос:

EXEC sp_help 'mytable'

и смотришь в 6th resultset возвращается.


чтобы узнать, что такое первичный ключ (предполагая, что ваша таблица dbo.T1):

select si.name as name,  
(case  when (si.status & 16) > 0 then 1 else 0 end) as isclust,
si.keycnt as keycnt,
si.indid as indid
from sysindexes si
left join sysobjects so on so.id = si.id 
where  si.indid > 0 
and  si.indid < 255 
and so.xtype <> 'S'
and so.id = OBJECT_ID('dbo.T1')
and (si.status & 2048) > 0

это даст вам что-то вроде:

name                                   isclust     keycnt indid
---------------------------------------------------------------
PK_T1                                      1           2      1

здесь у вас есть имя первичного ключа (PK_T1), будь то кластеризованный или нет, количество полей в нем (2) и идентификатор индекса (он вам понадобится позже).

далее выполнить следующее:

select INDEX_COL('dbo.T1', 1, 1) --returns Field1
select INDEX_COL('dbo.T1', 1, 2) --returns Field2

это даст вам имена двух полей из индекса. Первый параметр-это имя таблицы, второй-полученный идентификатор индекса ранее и третий цикл от 1 до keycnt (возвращается на предыдущем шаге).

имея эту информацию, вы сможете восстановить первичный ключ следующим образом:

ALTER TABLE dbo.T1 ADD CONSTRAINT PK_T1 PRIMARY KEY CLUSTERED (Field1, Field2)

Update: это может быть не так точно, как разбор результата sp_helpранее (вы пропустите порядок сортировки и файловую группу), но проще программно.


Не нарушайте ограничение PKEY. IMHO это лучшее решение, вы избежите затрат на восстановление PKEY и что, если вы не можете (дублировать оставшееся)?

или

прочитайте схему, чтобы узнать, как перестроить ограничение PKEY, а затем использовать ранее опубликованное решение.


Это может быть лучше SELECT вся ваша таблица во временную таблицу, делая преобразование на лету, если это возможно, а затем копируя его обратно. И если вы не можете преобразовать на лету, намного проще добавить простой индекс целочисленной строки в качестве первичного ключа во временной таблице.


ниже работало для меня (вы должны быть db_owner для выполнения этого действия)

--объявите переменную, чтобы получить contraints на таблице и назначить переменной

DECLARE @PK_CONST_NAME AS varchar(100)<br>
SET @PK_CONST_NAME = (SELECT NAME FROM SYS.KEY_CONSTRAINTS WHERE OBJECT_NAME(PARENT_OBJECT_ID) = '[TABLENAME]')

--переменные для хранения запросов

SET @DropAlterQuery = ''<br>
SET @RecreateAlterQuery = ''

-- Contruct Query

SET @DropAlterQuery = CONCAT('ALTER TABLE [TABLENAME] DROP CONSTRAINT ',@PK_CONST_NAME)

-- выполнение запроса, построенного для droping контрсилой

EXEC(@DropAlterQuery)

-- изменить размер столбца (Сейчас этот оператор работает как ограничения являются упал)

ALTER TABLE [TABLENAME]
ALTER COLUMN BATCH_ID VARCHAR(200) NOT NULL

-- Contruct Query

SET @RecreateAlterQuery = CONCAT(CONCAT('ALTER TABLE [TABLENAME] ADD CONSTRAINT ',@PK_CONST_NAME), ' PRIMARY KEY (<<PRIMARY KEY COLUMN1>>, <<PRIMARY KEY COLUMN2>>, <<PRIMARY KEY COLUMN2>>... So on)') 

-- выполнение запроса, построенного для воссоздания за контрсилой

EXEC(@RecreateAlterQuery)