Come trovo un vincolo predefinito utilizzando INFORMATION_SCHEMA?


116

Sto cercando di verificare se esiste un determinato vincolo predefinito. Non voglio usare la tabella sysobjects, ma la più standard INFORMATION_SCHEMA.

L'ho già usato per verificare la presenza di tabelle e vincoli di chiave primaria, ma non vedo i vincoli predefiniti da nessuna parte.

Non ci sono? (Sto usando MS SQL Server 2000).

EDIT: sto cercando di ottenere il nome del vincolo.

Risposte:


121

A quanto ho capito, i vincoli del valore predefinito non fanno parte dello standard ISO, quindi non vengono visualizzati in INFORMATION_SCHEMA. INFORMATION_SCHEMA sembra la scelta migliore per questo tipo di attività perché è multipiattaforma, ma se le informazioni non sono disponibili è necessario utilizzare le viste del catalogo degli oggetti (sys. *) Invece delle viste della tabella di sistema, che sono deprecate in SQL Server 2005 e versioni successive.

Di seguito è praticamente la stessa risposta di @ user186476. Restituisce il nome del vincolo del valore predefinito per una determinata colonna. (Per gli utenti non SQL Server, è necessario il nome del valore predefinito per eliminarlo e se non si nomina il vincolo predefinito da soli, SQL Server crea un nome pazzo come "DF_TableN_Colum_95AFE4B5". Per semplificare la modifica il tuo schema in futuro, dai sempre un nome esplicito ai tuoi vincoli!)

-- 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'

1
Nota: è possibile avere lo stesso nome di tabella in schemi diversi, quindi dovresti partecipare anche alla tabella sys.schemas.
Daniel James Bryars,

1
@DanielJamesBryars sys.schemas ora aggiunto alla query.
Stephen Turner

Si prega di vedere la mia risposta che è breve e dolce, funziona in tutte le versioni di SQL Server, non ha systabelle ed è facile da ricordare.
ErikE

2
@ErikE Il codice presume che il nome del vincolo predefinito sia noto. È un problema facile da risolvere, come dimostra il tuo codice. Buona risposta, domanda sbagliata.
DarLom

Il mio codice presume che, perché questo è ciò che l'interrogante ha chiesto: "Sto cercando di ottenere [se 'esiste un determinato vincolo predefinito']] dal nome del vincolo". Ho modificato la mia risposta per rendere molto più chiara la sua natura che soddisfa direttamente la domanda. Spero che aiuti.
ErikE

43

È possibile utilizzare quanto segue per restringere ulteriormente i risultati specificando il nome della tabella e il nome della colonna a cui è correlato il vincolo predefinito:

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'

1
Cerco questa semplice query da un paio d'ore. Thannnnnkkk youuuu!
Samuel,

Dovrebbe esserci o.xtype = 'D' per funzionare non è un database sensibile al maiuscolo / minuscolo.
IvanH

37

Sembra che non ci siano nomi di vincoli predefiniti nelle Information_Schemaviste.

utilizzare SELECT * FROM sysobjects WHERE xtype = 'D' AND name = @name per trovare un vincolo predefinito in base al nome


proprio quello di cui avevo bisogno. Grazie
drdwilcox

Risponde direttamente alla domanda meglio delle alternative successive (SQL 2000 e query in base al nome del vincolo).
Marc L.

Funziona solo quando si conosce il nome del vincolo, ma se il sistema è assegnato ...
TS

12

Lo script seguente elenca tutti i vincoli predefiniti e i valori predefiniti per le tabelle utente nel database in cui viene eseguito:

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

5

Se vuoi ottenere un vincolo dai nomi delle colonne o delle tabelle, o vuoi ottenere tutti i vincoli nel database, guarda ad altre risposte. Tuttavia, se stai solo cercando esattamente ciò che la domanda chiede, ovvero "verificare se esiste un determinato vincolo predefinito ... con il nome del vincolo" , allora c'è un modo molto più semplice.

Ecco una risposta a prova di futuro che non utilizza affatto le tabelle sysobjectso altre sys:

IF object_id('DF_CONSTRAINT_NAME', 'D') IS NOT NULL BEGIN
   -- constraint exists, work with it.
END

3
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

1
Un po 'più di spazio sarebbe bello, ma questo fa ciò che il poster originale ha chiesto utilizzando le viste del catalogo oggetti (sys. *), Che sono consigliate da Microsoft rispetto alle viste della tabella di sistema con compatibilità all'indietro.
Robert Calhoun

2

La colonna COLUMN_DEFAULT di INFORMATION_SCHEMA.COLUMNS è quello che stai cercando?


Sì e no, mi dice che c'è un valore predefinito e di cosa si tratta, ma mi serve anche il nome del vincolo.
WildJoe

1
Inoltre, tieni presente che se il tuo accesso SQL in runtime non possiede lo schema dbo, potresti trovare solo valori NULL nella colonna COLUMN_DEFAULT.
Glen Little

1
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

Necromancing.
Se è necessario solo verificare se esiste un vincolo
predefinito (i vincoli predefiniti possono avere un nome diverso in DB gestiti in modo inadeguato),
utilizzare 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 

Se vuoi controllare solo in base al nome del vincolo:

-- Alternative way: 
IF OBJECT_ID('DF_CONSTRAINT_NAME', 'D') IS NOT NULL 
BEGIN
    -- constraint exists, deal with it.
END 

E, ultimo ma non meno importante, puoi semplicemente creare una vista chiamata
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'
*/

0

Non penso che sia in INFORMATION_SCHEMA - probabilmente dovrai usare sysobjects o tabelle / viste deprecate correlate.

Penseresti che ci sarebbe un tipo per questo in INFORMATION_SCHEMA.TABLE_CONSTRAINTS, ma non ne vedo uno.


0

Probabilmente perché su alcuni degli altri DBMS SQL il "vincolo predefinito" non è realmente un vincolo, non troverai il suo nome in "INFORMATION_SCHEMA.TABLE_CONSTRAINTS", quindi la soluzione migliore è "INFORMATION_SCHEMA.COLUMNS" come altri hanno già menzionato.

(SQLServer-ignoramus qui)

L'unico motivo per cui riesco a pensare quando devi conoscere il nome del "vincolo predefinito" è se SQLServer non supporta il "ALTER TABLE xxx ALTER COLUMN yyy SET DEFAULT..."comando. Ma poi sei già in una zona non standard e devi usare i modi specifici del prodotto per ottenere ciò di cui hai bisogno.


0

Che ne dici di utilizzare una combinazione di CHECK_CONSTRAINTS e 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

CONSTRAINT_COLUMN_USAGE non contiene alcuna informazione sui vincoli predefiniti.
Stephen Turner

0

Sto usando il seguente script per recuperare tutti i valori predefiniti (sp_binddefaults) e tutti i vincoli predefiniti con i seguenti script:

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 = ''

0

Vista catalogo oggetti : sys.default_constraints

Le viste dello schema delle informazioni INFORMATION_SCHEMAsono conformi ANSI, ma i vincoli predefiniti non fanno parte dello standard ISO. Microsoft SQL Server fornisce visualizzazioni del catalogo di sistema per ottenere informazioni sui metadati degli oggetti di SQL Server.

sys.default_constraints vista del catalogo di sistema utilizzata per ottenere le informazioni sui vincoli predefiniti.

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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.