Как сделать столбец просмотра НЕ ПУСТОЙ

85

Я пытаюсь создать представление, в котором я хочу, чтобы столбец был только истинным или ложным. Однако кажется, что что бы я ни делал, SQL Server (2008) считает, что мой битовый столбец каким-то образом может быть нулевым.

У меня есть таблица под названием «Продукт» со столбцом «Статус», который есть INT, NULL. В представлении я хочу вернуть строку для каждой строки в продукте, для столбца BIT установлено значение true, если столбец Product.Status равен 3, в противном случае битовое поле должно иметь значение false.

Пример SQL

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

Если я сохраню этот запрос как представление и посмотрю на столбцы в обозревателе объектов, для столбца HasStatus будет установлено значение BIT, NULL. Но он никогда не должен быть NULL. Есть ли какой-нибудь волшебный трюк SQL, который я могу использовать, чтобы заставить этот столбец быть NOT NULL.

Обратите внимание, что если я удалю CAST()вокруг CASE, столбец будет правильно установлен как NOT NULL, но тогда будет установлен тип столбца INT, что не то, что я хочу. Я хочу, чтобы это было BIT. :-)

Рене
источник

Ответы:

152

Вы можете добиться того, чего хотите, немного изменив порядок запроса. Хитрость в том, что ISNULLдолжен быть снаружи, прежде чем SQL Server поймет, что результирующее значение никогда не будет NULL.

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

Одна из причин, по которой я считаю это полезным, - это использование ORM, когда вы не хотите, чтобы результирующее значение было сопоставлено с типом, допускающим значение NULL. Это может упростить задачу, если ваше приложение увидит, что значение никогда не может быть нулевым. Тогда вам не нужно писать код для обработки нулевых исключений и т. Д.

Д'Арси Риттич
источник
@Gunder: не беспокойтесь, на самом деле это немного загадочно. Это также удобно использовать при создании вычисляемого битового столбца в таблице и желании, чтобы результат не допускал значения NULL.
Д'Арси Риттич,
8
Мне нужно было что-то подобное, и я обнаружил, что COALESCE()это не работает, вам действительно нужно использоватьISNULL()
EvilBob22 06
@ EvilBob22 Это странно, потому что и COALESCE, и ISNULL могут возвращать NULL. Думаю, это просто причуда компилятора.
D'Arcy Rittich
1
Это, умноженное на миллиард, для того, чтобы EntityFramework могла вывести ключ, когда он обычно не может быть выведен.
Эрик,
1
См. Также: dba.stackexchange.com/questions/114260/…
emragins
3

К вашему сведению, для людей, сталкивающихся с этим сообщением, добавление ISNULL () снаружи приведения / преобразования может испортить оптимизатор в вашем представлении.

У нас было 2 таблицы, использующие то же значение, что и ключ индекса, но с типами разной числовой точности (плохо, я знаю), и наше представление объединяло их для получения окончательного результата. Но наш код промежуточного программного обеспечения искал определенный тип данных, и в представлении было CONVERT () вокруг возвращаемого столбца.

Я заметил, как и OP, что дескрипторы столбцов результата просмотра определили его как допускающий значение NULL, и я думал, что это первичный / внешний ключ для двух таблиц; зачем нам определять результат как допускающий значение NULL?

Я нашел этот пост, бросил ISNULL () вокруг столбца и вуаля - больше не допускает значения NULL.

Проблема заключалась в том, что производительность представления упала прямо в унитаз, когда запрос был отфильтрован по этому столбцу.

По какой-то причине явный CONVERT () в столбце результатов представления не испортил оптимизатор (он все равно должен был это сделать из-за разной точности), но добавление избыточной оболочки ISNULL () сделало это в большом путь.

user1664043
источник
Не могли бы вы показать решение, как обеспечить / указать недопустимость обнуления CONVERT()в примере, пожалуйста?
OR Mapper
1
Привет, ИЛИ - извините, я не видел этого некоторое время. Вот пример. Если у вас есть CONVERT (BIT, U.RETIRED), 0) AS Retired в вашем представлении, превращая, скажем, столбец byte или int в bit / bool, тогда он становится нулевым. Вы можете сделать этот столбец в своем представлении не допускающим значения NULL, заменив его на ISNULL (CONVERT (BIT, U.RETIRED), 0) AS Retired. Если U.RETIRED не был нулевым для запуска, он функционально ничего не меняет, кроме столбца в представлении. ВНИМАНИЕ: ISNULL () может помешать оптимизации запросов и выбору индикаторов.
user1664043
-3

Все, что вы можете делать с помощью оператора Select, - это управлять данными, которые ядро ​​базы данных отправляет вам как клиенту. Оператор select не влияет на структуру базовой таблицы. Чтобы изменить структуру таблицы, вам необходимо выполнить оператор Alter Table.

  1. Сначала убедитесь, что в этом битовом поле таблицы в настоящее время нет нулей.
  2. Затем выполните следующий оператор ddl: Alter Table dbo.Product Alter column status bit not null

Если, otoh, все, что вы пытаетесь сделать, это контролировать вывод представления, то того, что вы делаете, достаточно. Ваш синтаксис гарантирует, что вывод столбца HasStatus в наборе результатов представлений на самом деле никогда не будет нулевым. Он всегда будет либо значение бита = 1 или значение бита = 0. Не волнуйтесь , что говорит объект исследователь ...

Чарльз Бретана
источник
6
Я не хочу менять столбец таблицы. Столбец определяется как целочисленный столбец, допускающий значение NULL. Это соответствует нашей спецификации. Но мне нужно представление, которое возвращает столбец с битовым полем, которое не может быть нулевым. Недостаточно того, что я знаю, что он не может быть нулевым, столбец должен иметь значение NOT NULL, чтобы он правильно отображался в нашем ORM.
Рене