Этот баннер — требование Роскомнадзора для исполнения 152 ФЗ.
«На сайте осуществляется обработка файлов cookie, необходимых для работы сайта, а также для анализа использования сайта и улучшения предоставляемых сервисов с использованием метрической программы Яндекс.Метрика. Продолжая использовать сайт, вы даёте согласие с использованием данных технологий».
Политика конфиденциальности

Новые сообщения [новые:0]
Дайджест
Горячие темы
Избранное [новые:0]
Форумы
Пользователи
Статистика
Статистика нагрузки
Мод. лог
Поиск
|
|
14.10.2001, 16:04
|
|||
|---|---|---|---|
|
|||
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
Hi, All! В таблице имеется целочисленное поле (NS), которое допускает логический нуль (NULL). Нужно выполнять поиск по этому полю на предмет совпадения со значением переменной (@lNS_ID). В случае, когда параметр = NULL, требуется, чтобы возвращались записи со значением поля = NULL. Вот определение таблицы: CREATE TABLE dbo.ClassInf( ID bigint, Name varchar(255) NOT NULL, NS bigint NULL DEFAULT NULL, Parent bigint NULL DEFAULT NULL, CONSTRAINT PK_ClassInf PRIMARY KEY NONCLUSTERED (ID), CONSTRAINT FK_ClassInf_NS FOREIGN KEY (NS) REFERENCES dbo.Namespace, CONSTRAINT FK_ClassInf_Parent FOREIGN KEY (Parent) REFERENCES dbo.ClassInf, CONSTRAINT CKC_ClassInf_Unique UNIQUE CLUSTERED (Name, NS), CONSTRAINT CKC_ClassInf_Same CHECK( NULLIF(ID,Parent) is not NULL ) ) ON [PRIMARY] GO Пусть в dbo.ClassInf будет такое содержимое: ID Name NS Parent ------------------------------- 1; n11; 15; NULL 2; n22; NULL; NULL 3; n11; 10; 1 4; n22; 10; 1 5; n55; NULL; NULL Так выполняется запрос (значение @lNS_ID задано ранее и может быть NULL): declare @lParent_ID bigint select @lParent_ID = a.Parent from ClassInf a where a.Name = @vcName AND a.NS = @lNS_ID Проблема в том, что предикат '=' возвращает NULL в случае, когда один из аргументов NULL и, в результате, не находятся записи, где поле NS = NULL. Например, пусть @vcName = 'n22', а @lNS_ID = 10 - всё работает правильно. Найдётся запись: 4; n22; 10; 1 Если же @vcName = 'n22', а @lNS_ID = NULL, то надо, чтобы нашлась: 2; n22; NULL; NULL, но не найдётся ничего! Так как я не хочу зависеть от режима ANSI_NULLS (set ANSI_NULLS ON/OFF), то пришлось написать и использовать функцию: CREATE FUNCTION dbo.EQ3( @l1 bigint, @l2 bigint ) RETURNS int AS begin if( @l1 is NULL ) begin if( @l2 is NULL ) return 1 else return 0 end else begin if( @l2 is NULL ) return 0 else if( @l1 = @l2 ) return 1 else return 0 end return 0 end GO Исправить запрос: select @lParent_ID = a.Parent from ClassInf a where a.Name = @vcName AND dbo.EQ3(a.NS, @lNS_ID) = 1 --------------------------------------- У кого какие идеи - как это ещё можно реализовать, не используя составного предиката вида: where a.Name = @vcName AND (a.NS = @lNS_ID OR ((a.NS is null) and (@lNS_ID is null))) ? Thanks... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
15.10.2001, 02:13
|
|||
|---|---|---|---|
|
|||
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
declare @tmp table(s varchar(10)) insert into @tmp values('1') insert into @tmp values(null) select * from @tmp where s is null Что SET ANSI_NULLS ON, что SET ANSI_NULLS OFF работает правильно. Ведь Вы же сами в этой функции is null пишите, что там set не работает? В запросах всегда надо is null писать ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
15.10.2001, 06:37
|
|||
|---|---|---|---|
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
BIGINT, говорите? ну-ну... не иначе как каждый атом в Солнечной системе собрались пронумеровать и подписать к нему - в какую молекулу он входит, а та - в какой белок... а тот - в какую клетку... etc. (флаг в руки, конечно) может вот это вам поможет: SET NOCOUNT ON SET ANSI_DEFAULTS ON CREATE TABLE #join_source (parent_db char(5), parent_id int, firstname varchar(15)) CREATE TABLE #join_reference (child_db char(5), child_id int, surname varchar(15)) INSERT INTO #join_source SELECT 'MAIN1',1,'Андрей' INSERT INTO #join_source SELECT 'MAIN1',2,'Анатолий' INSERT INTO #join_source SELECT 'MAIN1',NULL,'Владимир' INSERT INTO #join_source SELECT 'MAIN1',4,'Олег' INSERT INTO #join_reference SELECT 'MAIN1',1,'Ларин' INSERT INTO #join_reference SELECT 'MAIN1',2,'Дукалис' INSERT INTO #join_reference SELECT 'MAIN1',NULL,'Казанцев' INSERT INTO #join_reference SELECT 'MAIN1',4,'Половцев' DECLARE @unreal_value int SELECT @unreal_value = 0x7FFFFFFF SELECT s.firstname, r.surname FROM #join_source s, #join_reference r WHERE ISNULL(s.parent_id,@unreal_value) = ISNULL(r.child_id,@unreal_value) AND s.parent_db = r.child_db ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
15.10.2001, 06:39
|
|||
|---|---|---|---|
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
1. допустим есть некое значение, которое в NS заведомо не будет(допустим -1) declare @lParent_ID bigint select @lParent_ID = a.Parent from ClassInf a where a.Name = @vcName AND coalesce(a.NS,-1) = coalesce(@lNS_ID,-1) 2. declare @lParent_ID bigint select @lParent_ID = (select a.Parent from ClassInf a where a.Name = @vcName AND a.NS = @lNS_ID union select a.Parent from ClassInf a where a.Name = @vcName and @lNS_ID is null and a.NS is null) Наверное есть еще варианты, но в любом случае получается некрасиво ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
15.10.2001, 08:44
|
|||
|---|---|---|---|
|
|||
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
А почему бы перед всем сравнением set ansi_nulls не сказать? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
15.10.2001, 11:45
|
|||
|---|---|---|---|
|
|||
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
Всем спасибо! Похоже, что наилучший вариант - использовать функцию: CREATE FUNCTION dbo.EQ3( @l1 bigint, @l2 bigint ). А насчёт bigint - тут важно не только число строк в таблице, но и частота обновления, ведь PK всё время увеличивается на 1 и когда-то произойдёт overwrap. PK снова станет 0, 1,... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
15.10.2001, 12:44
|
|||
|---|---|---|---|
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
используя функцию Вы должны осознавать, что отказываетесь от индексов. Если время пока не критично то это лучший вариант. а насчет bigint поддерживаю - нечегов в наше-то время экономить на байтах!(хотя и обычного Int наверняка вам хватит - если допустим нечто обновляется 10 раз в секунду, то у вас лет 300 есть. Или надеетесь что Ваша база проживёт дольше?) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
16.10.2001, 02:13
|
|||
|---|---|---|---|
|
|||
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
Вы меня конечно профи извините за точто я в вашу умную дисскуссию лезу, но почему не сказать if null = null set ansi_nulls off else set ansi_nulls off а потом set ansi_nulls on? или isnull(Exp, 1) не использовать? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
17.10.2001, 01:16
|
|||
|---|---|---|---|
|
|||
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
Я там с if напутал сгореча, но думаю придумать как можно. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
18.10.2001, 06:21
|
|||
|---|---|---|---|
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
Не знаю, попал в струю или нет, но приведу прием, который использую сам. Задача: выбрать значения из таблиц, у которых некие поля имеют одинаковые значения, либо в первой из этих таблиц поле содержит Null. Решение: select * from Table1 T1, Table2 T2 where IsNull(T1.SomeFld,T2.SomeFld)=T2.SomeFld Замечание. Прием работает для случаев, когда Table2 в поле SomeFld не содержит значений Null. В тех задачах, которыми я занимаюсь, обычно всегда это условие выполняется, поскольку речь идет о связке двух таблиц один-ко-многим, когда SomeFld является ключевым полем на стороне "один" (Table2) и одновременно Allow Nulls на стороне "многие" (Table1). ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|
19.10.2001, 10:53
|
|||
|---|---|---|---|
|
|||
Тонкости использования предиката '=' с NULL-значениями в SQL |
|||
|
#18+
Если значение -1 не встретится в выборке ( а так оно, скорее всего, и есть в Вашей задаче), то ниже приведённое решение будет использовать индексы. declare @lParent_ID bigint select top 1 @lParent_ID = a.Parent from ClassInf a where (a.Name = @vcName) AND (ISNULL(a.NS, -1) = ISNULL(@lNS_ID, -1)) Другое дело, что есть и ещё более правильный вариант declare @lParent_ID bigint select top 1 @lParent_ID = a.Parent from ClassInf a where (a.Name = @vcName) AND ( ((a.NS IS NOT NULL) AND (@lNS_ID IS NOT NULL) AND (a.NS = @lNS_ID)) OR ((a.NS IS NULL) AND (@lNS_ID IS NULL)) ) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
|
|
|

start [/forum/topic.php?fid=46&mobile=1&tid=1825264]: |
0ms |
get settings: |
8ms |
get forum list: |
15ms |
check forum access: |
3ms |
check topic access: |
3ms |
track hit: |
54ms |
get topic data: |
9ms |
get forum data: |
3ms |
get page messages: |
43ms |
get tp. blocked users: |
1ms |
| others: | 258ms |
| total: | 397ms |

| 0 / 0 |
