2010-02-24 5 views
65

J'essaye de créer une vue où je veux qu'une colonne soit vraie ou fausse. Cependant, il semble que peu importe ce que je fais, SQL Server (2008) pense que ma colonne de bits peut être nulle.Comment faire une colonne de vue NOT NULL

J'ai une table appelée "Produit" avec la colonne "Statut" qui est INT, NULL. Dans une vue, je souhaite renvoyer une ligne pour chaque ligne dans Product, avec une colonne BIT définie sur true si la colonne Product.Status est égale à 3, sinon le champ de bit doit être false.

Exemple SQL

SELECT CAST(CASE ISNULL(Status, 0) 
       WHEN 3 THEN 1 
       ELSE 0 
      END AS bit) AS HasStatus 
FROM dbo.Product 

Si j'enregistre cette requête en vue et regarder les colonnes dans l'Explorateur d'objets, la colonne HasStatus est réglé sur BIT, NULL. Mais il ne devrait jamais être NULL. Y at-il un truc magique magique que je peux utiliser pour forcer cette colonne à être NOT NULL.

Notez que, si je retire le CAST() autour de la CASE, la colonne est correctement réglée comme NOT NULL, mais le type de la colonne est réglée sur INT, ce qui est pas ce que je veux. Je veux que ce soit BIT. :-)

+0

@Gunder: +1, Bienvenue dans StackOverflow. J'ai formaté votre question, jetez un coup d'oeil à cela pour découvrir le formatage :) –

+0

Ahh, j'avais besoin d'un saut de ligne de plus avant le code. Merci. :-) –

Répondre

119

Vous pouvez obtenir ce que vous voulez en réarrangeant un peu votre requête. L'astuce est que le ISNULL doit être à l'extérieur avant que SQL Server ne comprenne que la valeur résultante ne peut jamais être NULL.

SELECT ISNULL(CAST(
    CASE Status 
     WHEN 3 THEN 1 
     ELSE 0 
    END AS bit), 0) AS HasStatus 
FROM dbo.Product 

L'une des raisons, je trouve cela utile est lorsque vous utilisez un ORM et vous ne voulez pas la valeur résultante mis en correspondance avec un type Nullable. Cela peut rendre les choses plus faciles si votre application considère que la valeur n'est jamais nulle. Ensuite, vous n'avez pas à écrire de code pour gérer les exceptions nulles, etc.

+0

Ça marche! - Merci beaucoup! - Je suis un peu gêné, je n'ai pas essayé ça en premier. :-) –

+0

@Gunder: pas de soucis, c'est un peu un arcane en fait. Cela est également pratique à utiliser lors de la création d'une colonne de bits calculée dans une table et si vous souhaitez que le résultat ne soit pas Nullable. – RedFilter

+4

J'avais besoin de quelque chose de similaire, et j'ai trouvé que 'COALESCE()' ne fonctionnait pas, vous devez * utiliser 'ISNULL() ' – EvilBob22

-1

Tout ce que vous pouvez faire dans une instruction Select est de contrôler les données que le moteur de base de données vous envoie en tant que client. L'instruction select n'a aucun effet sur la structure de la table sous-jacente. Pour modifier la structure de la table, vous devez exécuter une instruction Alter Table.

  1. D'abord, assurez-vous qu'il n'y a actuellement aucune nulls dans ce champ de bits dans le tableau
  2. Ensuite, exécutez l'instruction ddl suivante: Alter Table dbo.Product Alter column status bit not null

Si, Otoh, tous que vous essayez de faire est de contrôler la sortie de la vue, alors ce que vous faites est suffisant. Votre syntaxe garantira que la sortie de la colonne HasStatus dans le resultset sera en fait jamais être nulle. sera toujours soit valeur de bit = 1 soit valeur de bit = 0. Ne vous inquiétez pas de ce que dit l'explorateur d'objet ...

+5

Je ne veux pas changer la colonne de la table. La colonne est définie comme une colonne entière, qui autorise null. Cela correspond à nos spécifications. Mais j'ai besoin d'une vue qui retourne une colonne avec un champ de bits, qui ne peut pas être nul. Il ne suffit pas que je sache qu'il ne peut pas être nul, la colonne doit être NOT NULL, de sorte qu'elle sera mappée correctement dans notre ORM. –

0

Ceci est le code que j'utilise, il va rendre la colonne ID NOT NULL et toutes les autres NULL. Vous devez lancer la colonne bit ou varchar et comparer la colonne int à NULL.

CREATE TABLE [dbo].[aTestTable](
    [ID] [int] NOT NULL, 
    [varcharCol] [varchar](50) NOT NULL, 
    [nullvarcharCol] [varchar](50) NULL, 
    [bitCol] [bit] NOT NULL, 
    [nullbitCol] [bit] NULL, 
    [intCol] [int] NOT NULL, 
    [nullintCol] [int] NULL, 
CONSTRAINT [PK_aTestTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 


CREATE VIEW [dbo].[aTestView] 
AS 
SELECT ID , 
     NULLIF(varcharCol , '') AS varcharCol , 
     NULLIF(CAST(varcharCol AS VARCHAR), null) AS varcharCol1, --better 
     nullvarcharCol , 
     NULLIF(CAST(bitCol AS INT), null) AS bitCol , 
     nullbitCol , 
     NULLIF(CAST(intCol AS INT), NULL) AS intCol , 
     nullintCol 
FROM dbo.aTestTable 


Sample Data: 

ID varcharCol nullvarcharCol bitCol nullbitCol intCol nullintCol 
1 1 1 1 1 1 1 
2 0 0 0 0 0 0 
3 0 NULL 0 NULL 0 NULL 
4 a a 1 1 2 2 

HTH

3

Pour votre information, pour les personnes en cours d'exécution dans ce message, en ajoutant le ISNULL() autour de l'extérieur de la distribution/convertir peut gâcher l'optimiseur sur votre point de vue.

Nous avions 2 tables utilisant la même valeur qu'une clé d'index mais avec des types de précision numérique différente (mauvais, je sais) et notre vue se joignait à eux pour produire le résultat final. Mais notre code de middleware cherchait un type de données spécifique, et la vue avait une CONVERT() autour de la colonne retournée

J'ai remarqué, comme OP l'a fait, que les descripteurs de colonnes du résultat de la vue le définissaient comme nulle et que pensait que c'est une clé primaire/étrangère sur 2 tables; pourquoi voudrions-nous que le résultat soit défini comme nul?

J'ai trouvé ce post, lancé ISNULL() autour de la colonne et voila - non plus nul.

Problème était la performance de la vue est allé directement dans les toilettes quand une requête filtrée sur cette colonne. Pour une raison quelconque, un CONVERT() explicite sur la colonne résultat de la vue n'a pas bousillé l'optimiseur (il allait falloir le faire de toute façon à cause des différentes précisions) mais l'ajout d'un wrapper ISNULL() redondant , d'une grande façon.

+0

Pourriez-vous montrer la solution pour savoir comment assurer/indiquer une non-nullité avec 'CONVERT()' dans un exemple, s'il vous plaît? –

+1

Salut O. R. - désolé je n'ai pas vu cela pendant un moment. Voici un exemple. Si vous avez CONVERT (BIT, U.RETIRED), 0) AS Retired dans votre vue, en tournant un octet ou une colonne int dans un bit/bool, alors il devient nullable. Vous pouvez rendre cette colonne dans votre vue non-nullable en le remplaçant par ISNULL (CONVERT (BIT, U.RETIRED), 0) AS Retiré. Si U.RETIRED n'était pas nul pour démarrer, il ne change rien à la fonction sauf la colonne dans la vue. ATTENTION: l'ISNULL() peut interférer avec l'optimisation des requêtes et le choix des indices. – user1664043

Questions connexes