Jak sprawić, by kolumna widoku NIE była NULL

84

Próbuję utworzyć widok, w którym chcę, aby kolumna była tylko prawdą lub fałszem. Jednak wydaje się, że niezależnie od tego, co robię, SQL Server (2008) uważa, że ​​moja kolumna bitowa może być w jakiś sposób zerowa.

Mam tabelę o nazwie „Produkt” z kolumną „Status”, czyli INT, NULL. W widoku chcę zwrócić wiersz dla każdego wiersza w produkcie, z kolumną BIT ustawioną na wartość true, jeśli kolumna Product.Status jest równa 3, w przeciwnym razie pole bitu powinno mieć wartość false.

Przykład SQL

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

Jeśli zapiszę to zapytanie jako widok i spojrzę na kolumny w Eksploratorze obiektów, kolumna HasStatus jest ustawiona na BIT, NULL. Ale nigdy nie powinno być NULL. Czy jest jakaś magiczna sztuczka SQL, której mogę użyć, aby wymusić istnienie tej kolumny NOT NULL.

Zauważ, że jeśli usunę CAST()otaczającą CASEkolumnę, kolumna jest poprawnie ustawiona jako NOT NULL, ale wtedy typ kolumny jest ustawiony na INT, co nie jest tym, czego chcę. Chcę, żeby tak było BIT. :-)

René
źródło

Odpowiedzi:

150

Możesz osiągnąć to, co chcesz, zmieniając nieco swoje zapytanie. Sztuczka polega na tym, że ISNULLmusi znajdować się na zewnątrz, zanim SQL Server zrozumie, że wynikowa wartość nigdy nie może być NULL.

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

Jednym z powodów, dla których uważam to za przydatne, jest użycie ORM i nie chcesz, aby wynikowa wartość była mapowana na typ dopuszczający wartość null. Może to ułatwić wszystko, jeśli aplikacja uzna, że ​​wartość nigdy nie jest zerowa. Wtedy nie musisz pisać kodu obsługującego wyjątki o wartości null itp.

RedFilter
źródło
@Gunder: nie martw się, właściwie jest trochę tajemniczy. Jest to również przydatne podczas tworzenia kolumny bitów obliczeniowych w tabeli i chcesz, aby wynik nie dopuszczał wartości null.
RedFilter
8
Potrzebowałem czegoś podobnego i stwierdziłem, że COALESCE()nie działa, faktycznie musisz użyćISNULL()
EvilBob22
@ EvilBob22 To dziwne, ponieważ zarówno COALESCE, jak i ISNULL mogą zwrócić NULL. Myślę, że to tylko dziwactwo kompilatora.
RedFilter
1
To razy miliard, aby uzyskać EntityFramework, aby wywnioskować klucz, którego normalnie nie można wywnioskować.
Erik
3

FYI, dla ludzi, którzy natkną się na tę wiadomość, dodanie ISNULL () wokół zewnętrznej strony rzutowania / konwersji może zepsuć optymalizator w twoim widoku.

Mieliśmy 2 tabele używające tej samej wartości co klucz indeksu, ale z typami o różnej dokładności numerycznej (zła, wiem) i naszym zdaniem łączyliśmy je, aby uzyskać ostateczny wynik. Ale nasz kod oprogramowania pośredniego szukał określonego typu danych, a widok miał CONVERT () wokół zwróconej kolumny

Zauważyłem, podobnie jak OP, że deskryptory kolumn wyniku widoku definiują go jako dopuszczalny wartość null i myślałem, że jest to klucz podstawowy / obcy w 2 tabelach; dlaczego mielibyśmy chcieć, aby wynik był określony jako dopuszczalny wartości null?

Znalazłem ten post, rzuciłem ISNULL () wokół kolumny i voila - już nie dopuszcza wartości null.

Problem polegał na tym, że widok szedł prosto do toalety, gdy zapytanie przefiltrowało tę kolumnę.

Z jakiegoś powodu jawne CONVERT () w kolumnie wyników widoku nie zepsuło optymalizatora (i tak musiałby to zrobić z powodu różnych dokładności), ale dodanie nadmiarowego opakowania ISNULL () zrobiło to w dużym sposób.

user1664043
źródło
Czy mógłbyś pokazać rozwiązanie, jak zapewnić / wskazać brak wartości null CONVERT()w przykładzie, proszę?
LUB Mapper
1
Cześć LUB - przepraszam, nie widziałem tego przez chwilę. Oto przykład. Jeśli masz CONVERT (BIT, U.RETIRED), 0) AS Retired w twoim widoku, zamieniając powiedzmy bajt lub kolumnę int na bit / bool, wtedy staje się zerowa. Możesz sprawić, by ta kolumna w Twoim widoku nie dopuszczała wartości null, zastępując ją wartością ISNULL (CONVERT (BIT, U.RETIRED), 0) AS Retired. Jeśli U.RETIRED nie miał wartości null, aby rozpocząć, funkcjonalnie nie zmienia niczego poza kolumną w widoku. OSTRZEŻENIE: ISNULL () może kolidować z optymalizacją zapytań i wyborem wskazań.
user1664043
-3

Wszystko, co możesz zrobić w instrukcji Select, to kontrolować dane wysyłane przez silnik bazy danych do Ciebie jako klienta. Instrukcja select nie ma wpływu na strukturę tabeli bazowej. Aby zmodyfikować strukturę tabeli, należy wykonać instrukcję Alter Table.

  1. Najpierw upewnij się, że obecnie w tym polu bitu w tabeli nie ma żadnych wartości null
  2. Następnie wykonaj następującą instrukcję ddl: Alter Table dbo.Product Alter column status bit not null

Jeśli jedyne, co próbujesz zrobić, to kontrolować wyświetlanie widoku, to to, co robisz, jest wystarczające. Twoja składnia gwarantuje, że dane wyjściowe kolumny HasStatus w zestawie wyników widoków w rzeczywistości nigdy nie będą miały wartości NULL. Będzie ona zawsze być wartość bit = 1 lub nieco wartość = 0. Nie martw się, co mówi badacz obiekt ...

Charles Bretana
źródło
6
Nie chcę zmieniać kolumny tabeli. Kolumna jest zdefiniowana jako kolumna z liczbą całkowitą, która dopuszcza wartość null. To pasuje do naszej specyfikacji. Ale potrzebuję widoku, który zwraca kolumnę z polem bitowym, która nie może być pusta. Nie wystarczy, że wiem, że to nie może być null, kolumna musi być NIE NULL, aby poprawnie mapowała się w naszym ORM.
René