Как найти ограничение по умолчанию, используя INFORMATION_SCHEMA?
Я пытаюсь проверить, существует ли данное ограничение по умолчанию. Я не хочу использовать таблицу sysobjects, но более стандартную INFORMATION_SCHEMA.
Я использовал это для проверки таблиц и ограничений первичного ключа раньше, но я не вижу ограничений по умолчанию нигде.
Их там нет? (Я использую MS SQL Server 2000).
РЕДАКТИРОВАТЬ: Я ищу, чтобы получить имя ограничения.
16 ответов
Насколько я понимаю, ограничения по умолчанию не являются частью стандарта ISO, поэтому они не отображаются в INFORMATION_SCHEMA. INFORMATION_SCHEMA кажется лучшим выбором для такого рода задач, потому что он кроссплатформенный, но если информация недоступна, следует использовать представления каталога объектов (sys.*) Вместо представлений системных таблиц, которые не рекомендуются в SQL Server. 2005 и позже.
Ниже почти так же, как ответ @user186476. Возвращает имя ограничения по умолчанию для данного столбца. (Для пользователей, отличных от SQL Server, вам нужно имя по умолчанию, чтобы удалить его, и если вы сами не называете ограничение по умолчанию, SQL Server создает какое-то сумасшедшее имя, например "DF_TableN_Colum_95AFE4B5". Чтобы его было проще изменить ваша схема в будущем, всегда явно назовите ваши ограничения!)
-- returns name of a column's default value constraint
SELECT
default_constraints.name
FROM
sys.all_columns
INNER JOIN
sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN
sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
AND tables.name = 'tablename'
AND all_columns.name = 'columnname'
Вы можете использовать следующее, чтобы еще больше сузить результаты, указав Имя таблицы и Имя столбца, с которыми связано ограничение по умолчанию:
select * from sysobjects o
inner join syscolumns c
on o.id = c.cdefault
inner join sysobjects t
on c.id = t.id
where o.xtype = 'D'
and c.name = 'Column_Name'
and t.name = 'Table_Name'
Похоже, в именах ограничений по умолчанию нет Information_Schema
Просмотры.
использование SELECT * FROM sysobjects WHERE xtype = 'D' AND name = @name
найти ограничение по имени по имени
Сценарий ниже перечисляет все ограничения по умолчанию и значения по умолчанию для пользовательских таблиц в базе данных, в которой он выполняется:
SELECT
b.name AS TABLE_NAME,
d.name AS COLUMN_NAME,
a.name AS CONSTRAINT_NAME,
c.text AS DEFAULT_VALUE
FROM sys.sysobjects a INNER JOIN
(SELECT name, id
FROM sys.sysobjects
WHERE xtype = 'U') b on (a.parent_obj = b.id)
INNER JOIN sys.syscomments c ON (a.id = c.id)
INNER JOIN sys.syscolumns d ON (d.cdefault = a.id)
WHERE a.xtype = 'D'
ORDER BY b.name, a.name
Если вы хотите получить ограничение по именам столбцов или таблиц или хотите получить все ограничения в базе данных, посмотрите другие ответы. Однако, если вы просто ищете именно то, что задает вопрос, а именно: "проверить, существует ли данное ограничение по умолчанию... по имени ограничения", тогда есть гораздо более простой способ.
Вот ответ на будущее, который не использует sysobjects
или другой sys
таблицы вообще:
IF object_id('DF_CONSTRAINT_NAME', 'D') IS NOT NULL BEGIN
-- constraint exists, work with it.
END
Некромантинг.
Если вам нужно только проверить, существует ли ограничение по
умолчанию (ограничения по умолчанию могут иметь другое имя в плохо управляемых БД),
используйте INFORMATION_SCHEMA.COLUMNS (column_default):
IF NOT EXISTS(
SELECT * FROM INFORMATION_SCHEMA.COLUMNS
WHERE (1=1)
AND TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'T_VWS_PdfBibliothek'
AND COLUMN_NAME = 'PB_Text'
AND COLUMN_DEFAULT IS NOT NULL
)
BEGIN
EXECUTE('ALTER TABLE dbo.T_VWS_PdfBibliothek
ADD CONSTRAINT DF_T_VWS_PdfBibliothek_PB_Text DEFAULT (N''image'') FOR PB_Text;
');
END
Если вы хотите проверить только по имени ограничения:
-- Alternative way:
IF OBJECT_ID('DF_CONSTRAINT_NAME', 'D') IS NOT NULL
BEGIN
-- constraint exists, deal with it.
END
И последнее, но не менее важное: вы можете просто создать представление
INFORMATION_SCHEMA.DEFAULT_CONSTRAINTS:
CREATE VIEW INFORMATION_SCHEMA.DEFAULT_CONSTRAINTS
AS
SELECT
DB_NAME() AS CONSTRAINT_CATALOG
,csch.name AS CONSTRAINT_SCHEMA
,dc.name AS CONSTRAINT_NAME
,DB_NAME() AS TABLE_CATALOG
,sch.name AS TABLE_SCHEMA
,syst.name AS TABLE_NAME
,sysc.name AS COLUMN_NAME
,COLUMNPROPERTY(sysc.object_id, sysc.name, 'ordinal') AS ORDINAL_POSITION
,dc.type_desc AS CONSTRAINT_TYPE
,dc.definition AS COLUMN_DEFAULT
-- ,dc.create_date
-- ,dc.modify_date
FROM sys.columns AS sysc -- 46918 / 3892 with inner joins + where
-- FROM sys.all_columns AS sysc -- 55429 / 3892 with inner joins + where
INNER JOIN sys.tables AS syst
ON syst.object_id = sysc.object_id
INNER JOIN sys.schemas AS sch
ON sch.schema_id = syst.schema_id
INNER JOIN sys.default_constraints AS dc
ON sysc.default_object_id = dc.object_id
INNER JOIN sys.schemas AS csch
ON csch.schema_id = dc.schema_id
WHERE (1=1)
AND dc.is_ms_shipped = 0
/*
WHERE (1=1)
AND sch.name = 'dbo'
AND syst.name = 'tablename'
AND sysc.name = 'columnname'
*/
select c.name, col.name from sys.default_constraints c
inner join sys.columns col on col.default_object_id = c.object_id
inner join sys.objects o on o.object_id = c.parent_object_id
inner join sys.schemas s on s.schema_id = o.schema_id
where s.name = @SchemaName and o.name = @TableName and col.name = @ColumnName
Является ли столбец COLUMN_DEFAULT файла INFORMATION_SCHEMA.COLUMNS тем, что вы ищете?
WHILE EXISTS(
SELECT * FROM sys.all_columns
INNER JOIN sys.tables ST ON all_columns.object_id = ST.object_id
INNER JOIN sys.schemas ON ST.schema_id = schemas.schema_id
INNER JOIN sys.default_constraints ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
AND ST.name = 'MyTable'
)
BEGIN
DECLARE @SQL NVARCHAR(MAX) = N'';
SET @SQL = ( SELECT TOP 1
'ALTER TABLE ['+ schemas.name + '].[' + ST.name + '] DROP CONSTRAINT ' + default_constraints.name + ';'
FROM
sys.all_columns
INNER JOIN
sys.tables ST
ON all_columns.object_id = ST.object_id
INNER JOIN
sys.schemas
ON ST.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
AND ST.name = 'MyTable'
)
PRINT @SQL
EXECUTE sp_executesql @SQL
--End if Error
IF @@ERROR <> 0
BREAK
END
Если целевая база данных имеет, скажем, более 1 млн объектов, используяsys.default_constraints
может поразить вас 90%+ взятием при сканированииsys.syscolpars
с последующим поиском ключа дляdflt
вам, скорее всего, все равно. В моей БД требуется 1,129 с, чтобы собрать всего 4 строки из 158 прочитанных фактически отсканированных 1,12-миллиметровых строк с остаточным вводом-выводом .
При переходе на использование текущих таблиц/представлений sys.% с использованием запроса @Tim те же 4 ограничения получаются за 2 мс. Надеюсь, кто-то найдет это столь же полезным, как я нашел Тима:
SELECT ConstraintName = sdc.name
, SchemaName = ssch.name
, TableName = stab.name
, ColumnName = scol.name
FROM sys.objects sdc
INNER JOIN sys.columns scol
ON scol.default_object_id = sdc.object_id
INNER JOIN sys.objects stab
ON stab.object_id = scol.object_id
INNER JOIN sys.schemas ssch
ON ssch.schema_id = stab.schema_id;
Я не думаю, что это в INFORMATION_SCHEMA - вам, вероятно, придется использовать системные объекты или связанные устаревшие таблицы / представления.
Вы могли бы подумать, что для INFORMATION_SCHEMA.TABLE_CONSTRAINTS будет тип для этого, но я его не вижу.
Немного более чистый способ сделать это:
SELECT DC.[name]
FROM [sys].[default_constraints] AS DC
WHERE DC.[parent_object_id] = OBJECT_ID('[Schema].[TableName]')
Возможно, потому что в некоторых других СУБД SQL "ограничение по умолчанию" на самом деле не является ограничением, вы не найдете его имя в "INFORMATION_SCHEMA.TABLE_CONSTRAINTS", поэтому лучше всего ставить "INFORMATION_SCHEMA.COLUMNS", как уже упоминали другие.
(SQLServer-невежда здесь)
Единственная причина, по которой я могу придумать, когда нужно знать имя "ограничения по умолчанию", заключается в том, что SQLServer не поддерживает "ALTER TABLE xxx ALTER COLUMN yyy SET DEFAULT..."
команда. Но тогда вы уже находитесь в нестандартной зоне, и вам нужно использовать специфичные для продукта способы, чтобы получить то, что вам нужно.
Как насчет использования комбинации CHECK_CONSTRAINTS и CONSTRAINT_COLUMN_USAGE:
select columns.table_name,columns.column_name,columns.column_default,checks.constraint_name
from information_schema.columns columns
inner join information_schema.constraint_column_usage usage on
columns.column_name = usage.column_name and columns.table_name = usage.table_name
inner join information_schema.check_constraints checks on usage.constraint_name = checks.constraint_name
where columns.column_default is not null
Я использую следующий скрипт для получения всех значений по умолчанию (sp_binddefaults) и всех ограничений по умолчанию со следующими сценариями:
SELECT
t.name AS TableName, c.name AS ColumnName, SC.COLUMN_DEFAULT AS DefaultValue, dc.name AS DefaultConstraintName
FROM
sys.all_columns c
JOIN sys.tables t ON c.object_id = t.object_id
JOIN sys.schemas s ON t.schema_id = s.schema_id
LEFT JOIN sys.default_constraints dc ON c.default_object_id = dc.object_id
LEFT JOIN INFORMATION_SCHEMA.COLUMNS SC ON (SC.TABLE_NAME = t.name AND SC.COLUMN_NAME = c.name)
WHERE
SC.COLUMN_DEFAULT IS NOT NULL
--WHERE t.name = '' and c.name = ''
Просмотр каталога объектов: sys.default_constraints
Представления информационной схемы INFORMATION_SCHEMA
ANSI-совместимы, но ограничения по умолчанию не являются частью стандарта ISO. Microsoft SQL Server предоставляет представления системного каталога для получения информации о метаданных объекта SQL Server.
sys.default_constraints
представление системного каталога, используемое для получения информации об ограничениях по умолчанию.
SELECT so.object_id TableName,
ss.name AS TableSchema,
cc.name AS Name,
cc.object_id AS ObjectID,
sc.name AS ColumnName,
cc.parent_column_id AS ColumnID,
cc.definition AS Defination,
CONVERT(BIT,
CASE cc.is_system_named
WHEN 1
THEN 1
ELSE 0
END) AS IsSystemNamed,
cc.create_date AS CreationDate,
cc.modify_date AS LastModifiednDate
FROM sys.default_constraints cc WITH (NOLOCK)
INNER JOIN sys.objects so WITH (NOLOCK) ON so.object_id = cc.parent_object_id
LEFT JOIN sys.schemas ss WITH (NOLOCK) ON ss.schema_id = so.schema_id
LEFT JOIN sys.columns sc WITH (NOLOCK) ON sc.column_id = cc.parent_column_id
AND sc.object_id = cc.parent_object_id
ORDER BY so.name,
cc.name;