Как отключить ограничение первичного ключа программно?
У меня есть таблица с первичным ключом в моей таблице 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)