Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Scopri se un vincolo CHECK è a livello di colonna o di tabella in SQL Server (esempi T-SQL)

Quando crei un CHECK vincolo in SQL Server, potresti non pensare nemmeno se si tratti di un vincolo a livello di tabella o di un vincolo a livello di colonna.

Un CHECK a livello di tabella vincolo si applica alla tabella, mentre un vincolo a livello di colonna si applica a una colonna specifica. Con un CHECK a livello di tabella vincolo, è la riga che viene controllata quando controlla i dati. Con un CHECK a livello di colonna vincolo, è la colonna specifica che viene selezionata.

Generalmente saprai se il vincolo che stai creando è un vincolo a livello di tabella o di colonna dalla definizione che gli dai. Se nell'espressione viene selezionata solo una colonna, sarà un vincolo a livello di colonna. Altrimenti sarà un vincolo a livello di tabella.

Ma come fai a sapere se i tuoi vincoli esistenti sono a livello di colonna o di tabella?

Puoi eseguire uno qualsiasi degli esempi di codice seguenti per determinare se i tuoi vincoli esistenti sono a livello di colonna o di tabella. Questi recuperano tutti i CHECK vincoli per il database corrente, ma puoi sempre usare un WHERE clausola per restringerla a un vincolo specifico.

Esempio 1 – Query di base

Ecco una semplice query che restituisce informazioni di base su tutti i CHECK vincoli nel database corrente.

Qui, interrogo il sys.check_constraints vista di sistema (che restituisce una riga per ogni oggetto che è un CHECK vincolo, con sys.objects.type = 'C' ). Restituisco solo quattro colonne (ma sentiti libero di restituire tutte le colonne che desideri).

SELECT 
  Name,
  OBJECT_NAME(parent_object_id) AS 'Table',
  parent_column_id,
  Definition
FROM sys.check_constraints;

Risultato:

+-----------------+----------------+--------------------+----------------------------------------+
| Name            | Table          | parent_column_id   | Definition                             |
|-----------------+----------------+--------------------+----------------------------------------|
| chkPrice        | ConstraintTest | 2                  | ([Price]>(0))                          |
| chkValidEndDate | ConstraintTest | 0                  | ([EndDate]>=[StartDate])               |
| chkTeamSize     | ConstraintTest | 3                  | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
| chkJobTitle     | Occupation     | 3                  | ([JobTitle]<>'Digital Nomad')          |
+-----------------+----------------+--------------------+----------------------------------------+

Il modo più rapido per determinare quali vincoli sono vincoli a livello di tabella è cercare lo zero ( 0 ) in parent_column_id colonna. Qualsiasi cosa con uno zero è un CHECK a livello di tabella vincolo. Un valore diverso da zero indica che si tratta di un CHECK a livello di colonna vincolo definito sulla colonna con il valore ID specificato.

Quindi in questo esempio ci sono tre vincoli a livello di colonna e un vincolo a livello di tabella.

Nota che ci sono due vincoli con lo stesso parent_column_id (3), tuttavia, questi due vincoli provengono da tabelle diverse. Il 3 si riferisce alla terza colonna delle rispettive tabelle.

Come accennato, se vuoi solo informazioni su un vincolo specifico, usa un WHERE clausola:

SELECT 
  Name,
  OBJECT_NAME(parent_object_id) AS 'Table',
  parent_column_id,
  Definition
FROM sys.check_constraints
WHERE name = 'chkPrice';

Risultato:

+----------+----------------+--------------------+---------------+
| Name     | Table          | parent_column_id   | Definition    |
|----------+----------------+--------------------+---------------|
| chkPrice | ConstraintTest | 2                  | ([Price]>(0)) |
+----------+----------------+--------------------+---------------+

Esempio 2 – Migliora la query

Possiamo migliorare l'esempio precedente restituendo il nome della colonna padre anziché solo il suo ID. Ovviamente, questo restituirà il nome della colonna solo per i vincoli a livello di colonna. Per i vincoli a livello di tabella verrà restituito NULL.

SELECT 
  cc.name AS 'Constraint',
  o.name AS 'Table',
  ac.name AS 'Column',
  cc.Definition AS 'Constraint Definition'
FROM sys.check_constraints cc
LEFT OUTER JOIN sys.objects o
  ON cc.parent_object_id = o.object_id
LEFT OUTER JOIN sys.all_columns ac
  ON cc.parent_column_id = ac.column_id
  AND cc.parent_object_id = ac.object_id;

Risultato:

+-----------------+----------------+----------+----------------------------------------+
| Constraint      | Table          | Column   | Constraint Definition                  |
|-----------------+----------------+----------+----------------------------------------|
| chkPrice        | ConstraintTest | Price    | ([Price]>(0))                          |
| chkValidEndDate | ConstraintTest | NULL     | ([EndDate]>=[StartDate])               |
| chkTeamSize     | ConstraintTest | TeamSize | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
| chkJobTitle     | Occupation     | JobTitle | ([JobTitle]<>'Digital Nomad')          |
+-----------------+----------------+----------+----------------------------------------+

Esempio 3 – Ulteriori miglioramenti

Modifichiamo ancora la query:

SELECT 
  cc.name AS 'Constraint',
  cc.is_disabled AS 'Disabled?',
  CASE WHEN cc.parent_column_id = 0
    THEN 'Table-level'
    ELSE 'Column-level'
    END AS 'Table/Column',
  o.name AS 'Table',
  ISNULL(ac.name, '(n/a)') AS 'Column',
  cc.Definition AS 'Constraint Definition'
FROM sys.check_constraints cc
LEFT OUTER JOIN sys.objects o
  ON cc.parent_object_id = o.object_id
LEFT OUTER JOIN sys.all_columns ac
  ON cc.parent_column_id = ac.column_id
  AND cc.parent_object_id = ac.object_id;

Risultato:

+-----------------+-------------+----------------+----------------+----------+----------------------------------------+
| Constraint      | Disabled?   | Table/Column   | Table          | Column   | Constraint Definition                  |
|-----------------+-------------+----------------+----------------+----------+----------------------------------------|
| chkPrice        | 0           | Column-level   | ConstraintTest | Price    | ([Price]>(0))                          |
| chkValidEndDate | 0           | Table-level    | ConstraintTest | (n/a)    | ([EndDate]>=[StartDate])               |
| chkTeamSize     | 0           | Column-level   | ConstraintTest | TeamSize | ([TeamSize]>=(5) AND [TeamSize]<=(20)) |
| chkJobTitle     | 0           | Column-level   | Occupation     | JobTitle | ([JobTitle]<>'Digital Nomad')          |
+-----------------+-------------+----------------+----------------+----------+----------------------------------------+

Quindi ora ho il testo "a livello di colonna" o "a livello di tabella", a seconda di quale sia.

Uso anche ISNULL() funzione per trasformare qualsiasi valore NULL in "(n/a)".

E ho anche aggiunto is_disabled colonna all'elenco, nel caso in cui uno qualsiasi dei vincoli sia stato disabilitato. Puoi sempre dare a questa colonna lo stesso trattamento riservato a parent_column_id colonna e presentare "Sì" o "No" o "Abilitato" o "Disabilitato" o simili.