Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment trouver l'identificateur unique optimal dans une table dans SQL Server :sp_special_columns

Dans SQL Server, vous pouvez utiliser le sp_special_columns procédure stockée système pour identifier un identifiant unique pour la table. Plus précisément, il renvoie l'ensemble optimal de colonnes qui identifient de manière unique une ligne dans la table. Il renvoie également des colonnes automatiquement mises à jour lorsqu'une valeur de la ligne est mise à jour par une transaction.

sp_special_columns est équivalent à SQLSpecialColumns dans ODBC.

S'il n'y a pas de colonnes qui peuvent identifier de manière unique la table, le jeu de résultats est vide.

Syntaxe

La syntaxe ressemble à ceci :

sp_special_columns [ @table_name = ] 'table_name'     
     [ , [ @table_owner = ] 'table_owner' ]   
     [ , [ @qualifier = ] 'qualifier' ]   
     [ , [ @col_type = ] 'col_type' ]   
     [ , [ @scope = ] 'scope' ]  
     [ , [ @nullable = ] 'nullable' ]   
     [ , [ @ODBCVer = ] 'ODBCVer' ]   
[ ; ]

Le @table_name argumentaire est nécessaire. Les autres sont facultatifs. Consultez la documentation de Microsoft pour une explication détaillée de chaque argument.

Exemple 1 - Colonne de clé primaire

Voici un exemple de base par rapport à une table avec une colonne de clé primaire appelée PersonId :

EXEC sp_special_columns Person;

Il peut également être exécuté comme ceci :

EXEC sp_special_columns @table_name = 'Person';

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | PersonId      | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

Dans ce cas, la colonne de clé primaire est renvoyée. Je sais qu'il s'agit de la colonne de clé primaire, car j'ai créé la table avec le code suivant :

CREATE TABLE Person (
  PersonId int primary key, 
  PersonName varchar(500)
  );

Il semble donc que la procédure stockée ait en fait renvoyé la colonne optimale qui identifie de manière unique cette table.

Exemple 2 – Colonne UNIQUE

La table de cet exemple n'a pas de clé primaire, mais elle a un UNIQUE contrainte.

Voici le code utilisé pour créer le tableau :

CREATE TABLE Event (
  EventId int UNIQUE, 
  EventName varchar(500)
  );

Alors exécutons maintenant sp_special_columns contre cette table :

EXEC sp_special_columns Event;

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | EventId       | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

Dans ce cas, la colonne avec le UNIQUE contrainte est considérée comme l'identifiant unique optimal.

Cependant, cela ne signifie pas nécessairement que tout colonne contrainte par un UNIQUE contrainte sera automatiquement considérée comme un identifiant unique. Le résultat peut dépendre de la manière dont les valeurs nulles sont traitées.

Exemple 3 - L'argument @nullable

Vous pouvez utiliser le @nullable argument pour spécifier si les colonnes spéciales peuvent accepter une valeur nulle.

Ici, j'exécute à nouveau le même code, sauf que cette fois j'utilise @nullable = 'O' .

EXEC sp_special_columns 
  Event, 
  @nullable = 'O';

Résultat :

(0 rows affected)

Ici, il utilise @nullable = 'U'

EXEC sp_special_columns 
  Event, 
  @nullable = 'U';

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | EventId       | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

O spécifie des colonnes spéciales qui n'autorisent pas les valeurs nulles. U spécifie les colonnes qui sont partiellement nullables. U est la valeur par défaut.

Voici ce qui se passe si je crée la colonne en tant que NOT NULL :

DROP TABLE Event;

CREATE TABLE Event (
  EventId int NOT NULL UNIQUE, 
  EventName varchar(500)
  );

EXEC sp_special_columns 
  Event, 
  @nullable = 'U';

EXEC sp_special_columns 
  Event, 
  @nullable = 'O';

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | EventId       | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
(1 row affected)
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | EventId       | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
(1 row affected)

Cette fois les deux O et U produit le même résultat.

Si vous avez une table avec plusieurs UNIQUE colonnes de contrainte, et certains autorisent les valeurs nulles tandis que d'autres ne le font pas, cet argument peut avoir un impact sur celui qui est considéré comme l'identifiant unique optimal. Voir l'exemple 7 au bas de cet article pour un exemple de ce que je veux dire.

Exemple 4 - Colonne IDENTITY

La table de cet exemple n'a pas de clé primaire ni de UNIQUE contrainte, mais elle a une IDENTITY colonne.

Voici le code utilisé pour créer le tableau :

CREATE TABLE Product (
  ProductId int IDENTITY, 
  ProductName varchar(500)
  );

Alors exécutons maintenant sp_special_columns contre cette table :

EXEC sp_special_columns Product;

Résultat :

(0 rows affected)

Il semble donc que IDENTITY n'est pas suffisant pour identifier de manière unique cette table.

Exemple 5 - Clé primaire multicolonne

En voici un avec une clé primaire multicolonne. Dans ce cas, deux colonnes sont utilisées pour la clé primaire.

Voici le code utilisé pour créer le tableau :

CREATE TABLE PersonProduct (
  PersonId int, 
  ProductId int,
   CONSTRAINT PK_PersonProduct PRIMARY KEY (PersonId, ProductId)
  ); 

Alors exécutons maintenant sp_special_columns contre cette table :

EXEC sp_special_columns PersonProduct;

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | PersonId      | 4           | int         | 10          | 4        | 0       | 1               |
| 1       | ProductId     | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

Exemple 6 - Clé primaire et contrainte UNIQUE

Et s'il y a une clé primaire et un UNIQUE contrainte dans la même table ?

Découvrons :

CREATE TABLE PersonEvent (
  PersonEventId int UNIQUE,
  PersonId int, 
  EventId int,
   CONSTRAINT PK_PersonEvent PRIMARY KEY (PersonId, EventId)
  );

Exécutez sp_special_columns contre cette table :

EXEC sp_special_columns PersonEvent;

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | PersonId      | 4           | int         | 10          | 4        | 0       | 1               |
| 1       | EventId       | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

La clé primaire a gagné.

Et si on échangeait la clé primaire et le UNIQUE colonnes clés autour ?

OK, créons une autre table entière juste pour ça :

CREATE TABLE PersonEvent2 (
  PersonEventId int PRIMARY KEY,
  PersonId int UNIQUE, 
  EventId int UNIQUE
  ); 

Exécutez sp_special_columns contre cette table :

EXEC sp_special_columns PersonEvent2;

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | PersonEventId | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

La clé primaire a donc de nouveau gagné.

Exemple 7 - Beaucoup de contraintes UNIQUES

Et si chaque la colonne a un UNIQUE contrainte ?

CREATE TABLE Event2 (
  EventId int UNIQUE, 
  EventName varchar(500) UNIQUE,
  StartDate date UNIQUE,
  EndDate date UNIQUE
  );

Exécutez sp_special_columns contre cette table :

EXEC sp_special_columns Event2;

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | EndDate       | -9          | date        | 10          | 20       | NULL    | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

Mais voyons ce qui se passe si nous définissons l'une de ces colonnes sur NOT NULL , puis utilisez @nullable = 'O' :

DROP TABLE Event2;

CREATE TABLE Event2 (
  EventId int NOT NULL UNIQUE, 
  EventName varchar(500) UNIQUE,
  StartDate date UNIQUE,
  EndDate date UNIQUE
  );

Exécutez sp_special_columns avec @nullable = 'O' :

EXEC sp_special_columns 
  Event2,
  @nullable = 'O'; 

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | EventId       | 4           | int         | 10          | 4        | 0       | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

Ainsi, la colonne "not nullable" est maintenant choisie comme identifiant unique optimal.

Exécutons maintenant sp_special_columns avec @nullable = 'U' :

EXEC sp_special_columns 
  Event2,
  @nullable = 'U';

Résultat :

+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+
| SCOPE   | COLUMN_NAME   | DATA_TYPE   | TYPE_NAME   | PRECISION   | LENGTH   | SCALE   | PSEUDO_COLUMN   |
|---------+---------------+-------------+-------------+-------------+----------+---------+-----------------|
| 1       | EndDate       | -9          | date        | 10          | 20       | NULL    | 1               |
+---------+---------------+-------------+-------------+-------------+----------+---------+-----------------+

Il est maintenant de retour à la colonne précédente.