Как отключить ограничение первичного ключа программно? - PullRequest
6 голосов
/ 10 апреля 2009

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

Нарушение ограничения PRIMARY KEY 'PK_Name'. Невозможно вставить повторяющийся ключ в объект 'dbo.Table'.

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

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

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

Ответы [ 6 ]

16 голосов
/ 10 апреля 2009
ALTER TABLE mytable DROP CONSTRAINT PK_Name

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

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

Раскомментируйте CLUSTERED, если хотите, чтобы ваш PRIMARY KEY был кластеризован (т.е. упорядочены сами строки таблицы)

Чтобы выяснить, кластеризован ли PRIMARY KEY, введите:

EXEC sp_help 'mytable'

и посмотрите возвращенный набор результатов 6th.

5 голосов
/ 10 апреля 2009

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

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

2 голосов
/ 10 апреля 2009

Чтобы узнать, что является первичным ключом (при условии, что ваша таблица 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)

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

0 голосов
/ 26 декабря 2017

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

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

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)

- Выполнение запроса, созданного для удаления ограничений

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)
0 голосов
/ 10 апреля 2009

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

0 голосов
/ 10 апреля 2009

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

OR

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...