Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[MSSQL] = null <> is null

Pagina: 1
Acties:

  • siroki
  • Registratie: Oktober 2006
  • Laatst online: 18-10 10:58
Hoi,

Stel je hebt de volgende stored procedure:

------------------------------------
create procedure spTest

@langID int

as

select * from tabel where langID = @langID
-----------------------------------

Op zich heel simpel. Vanuit de applicatie stuur ik een ID mee, en dan geeft de stored procedure netjes een record terug. Edoch! LangID kan ook NULL zijn! Als ik een lege waarde naar @langID stuur dan zou hij dat in de stored procedure omzetten naar:

select * from tabel where langID = '';

Logisch dat je dan niets terug krijgt, want '' is niet gelijk aan NULL.

Wat ik dan had bedacht is deze regel in de stored procedure erbij te zetten:

if(@langID = '') set @langID = null

Je zou zeggen dat dat dan goed komt. Helaas krijg ik dan ook geen regels terug.

Ik kan natuurlijk de query in de stored procedure zodanig aanpassen dat ik voor lege waardes en niet lege waardes twee queries uit ga voeren, maar dit is natuurlijk een simpel voorbeeld. Mijn applicatie heeft honderden stored procedures die bijna allemaal van LangID gebruik maken.

Iemand een idee hoe ik dit kan oplossen?

Ik wil dus met 1 query regels met een gevulde als een null langID kunnen ophalen.

Bedankt alvast.

  • DamadmOO
  • Registratie: Maart 2005
  • Laatst online: 19:04
Om te kijken of een waarde in een veld NULL is moet je gebruik maken van de IS NULL expressie in je query.

Dus het moet dan worden:
SELECT * FROM tabel WHERE langID IS NULL

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Set de default waarde op
code:
1
''
, en controlleer op
code:
1
var = ''

Going for adventure, lots of sun and a convertible! | GMT-8


  • P_de_B
  • Registratie: Juli 2003
  • Niet online
NULL is per definitie ongelijk aan NULL.

code:
1
WHERE ISNULL(langId, "") = ""


Dit vervangt alle waardes NULL in <langId> door "". Nog beter zou zijn om gewoon "" niet toe te staan als waarde voor 'onbekend'....

Oops! Google Chrome could not find www.rijks%20museum.nl


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Quickfix: maak LangID non-nullable en zet als default value '-1'. Vervolgens kun je leeg ('') gelijkstellen aan -1 en werkt je query wel. Ik ben er wel vanuit gegaan dat LangID normaal alleen positief is.

If it isn't broken, fix it until it is..


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-11 23:43

.oisyn

Moderator Devschuur®

Demotivational Speaker

@Niemand_Anders: ja, handig, laten we een speciale database feature om dingen als ongedefinieerd te kunnen markeren met perfect gedefinieerde tristate logic omzeilen door zelf maar wat te prutsen middels een arbitraire waarde die staat voor ongedefinieerd 8)7. Bovendien gaat dat al niet werken als er een fatsoenlijke foreign key constraint op die landID zit (aangenomen dat het een id is die naar een andere tabel wijst). En de eerste die voorstelt om dan ook maar een dummy rij in de Lang tabel te zetten met id=-1 verdient een bitch-slap :P


SQL:
1
select * from tabel where langID = @langID OR (@langID = '' AND langID IS NULL)


.edit:
Damn you Bosmonster... *slap* :P

[ Voor 15% gewijzigd door .oisyn op 11-02-2008 12:32 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Bosmonster
  • Registratie: Juni 2001
  • Laatst online: 19-11 09:49

Bosmonster

*zucht*

.oisyn schreef op maandag 11 februari 2008 @ 12:07:
@Niemand_Anders: ja, handig, laten we een speciale database feature om dingen als ongedefinieerd te kunnen markeren met perfect gedefinieerde tristate logic omzeilen door zelf maar wat te prutsen middels een arbitraire waarde die staat voor ongedefinieerd 8)7. Bovendien gaat dat al niet werken als er een fatsoenlijke foreign key constraint op die landID zit (aangenomen dat het een id is die naar een andere tabel wijst). En de eerste die voorstelt om dan ook maar een dummy rij in de Lang tabel te zetten met id=-1 verdient een bitch-slap :P

SQL:
1
select * from tabel where langID = @langID OR (@langID = '' AND langID IS NULL)
Ik zou denk ik toch een dummy rij in de Lang tabel zetten met id=-1

  • justmental
  • Registratie: April 2000
  • Niet online

justmental

my heart, the beat

.oisyn schreef op maandag 11 februari 2008 @ 12:07:
En de eerste die voorstelt om dan ook maar een dummy rij in de Lang tabel te zetten met id=-1 verdient een bitch-slap :P

SQL:
1
select * from tabel where langID = @langID OR (@langID = '' AND langID IS NULL)
Zo heb ik er ook eentje:
De eerste die voorstelt 2 functionaliteiten in 1 query te vatten met 'OR parameter = constante' verdient een bitch-slap :P
Een database maakt per query 1 executieplan, door die switch moet hij uitgaan van beide mogelijkheden en een plan verzinnen die beide kan, wat hij dan toepast op alle parameter waarden.
Als je bijvoorbeeld een index hebt op langID dan zal deze nooit gebruikt kunnen worden omdat de query parser niet weet wat er in de binds staat.
Tenzij mssql een soort bind peeking hanteert bij elke executie en vervolgens het plan aanpast, maar dat lijkt me sterk

Who is John Galt?


  • LuCarD
  • Registratie: Januari 2000
  • Niet online

LuCarD

Certified BUFH

code:
1
2
3
4
5
6
7
8
9
create procedure spTest

@langID int 

as
if @langID = "" 
 select * from tabel where langID is null
else
 select * from tabel where langID = @langID


zoiets?

of
code:
1
2
3
4
5
6
7
8
9
create procedure spTest

@langID int = NULL

as
if @langID is NULL
 select * from tabel where langID is null
else
 select * from tabel where langID = @langID

[ Voor 33% gewijzigd door LuCarD op 11-02-2008 12:48 ]

Programmer - an organism that turns coffee into software.


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Altijd 'IF' statements vermijden in queries als je kunt, want een IF is in de regel de oorzaak van een recompile per executie.

Wat je moet gebruiken is COALESCE. In je voorbeeld geef je aan '' als leeg, wat onzin is, want je LangID is van het type int. Je moet dus een magic value verzinnen die 'leeg' representeert. Aangezien LangID waarschijnlijk een FK is, is LangID altijd positief neem ik aan. Dus als je NULL meegeeft aan de proc, je dus ook alleen de regels terugkrijgt die GEEN LangID value hebben:

select * from table where COALESCE(LangID, -1) == COALESCE(@LangID, -1)

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-11 23:43

.oisyn

Moderator Devschuur®

Demotivational Speaker

justmental schreef op maandag 11 februari 2008 @ 12:40:
De eerste die voorstelt 2 functionaliteiten in 1 query te vatten met 'OR parameter = constante' verdient een bitch-slap :P
Nou nou, ik vind een fout datamodel wat zorgwekkender dan een ongeoptimaliseerde query :)
Als je bijvoorbeeld een index hebt op langID dan zal deze nooit gebruikt kunnen worden omdat de query parser niet weet wat er in de binds staat.
Nou ben ik geen db guru, maar ik zie niet in waarom er bij een dergelijke query geen index gebruikt kan worden eigenlijk... Hij moet @langID en NULL opzoeken, en die NULL velden kunnen vervolgens worden gefiltered aan de hand van de waarde van @langID. Fair enough, aparte queries is waarschijnlijk optimaler, maar dat dit meteen al een index bypassed?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 19-11 23:43

.oisyn

Moderator Devschuur®

Demotivational Speaker

EfBe schreef op maandag 11 februari 2008 @ 12:57:
Wat je moet gebruiken is COALESCE.
Just out of interest, is jouw query beter dan de mijne waar de OR in staat? En zo ja, waarom?

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • justmental
  • Registratie: April 2000
  • Niet online

justmental

my heart, the beat

.oisyn schreef op maandag 11 februari 2008 @ 12:57:
Nou nou, ik vind een fout datamodel wat zorgwekkender dan een ongeoptimaliseerde query :)
Eens, ik reageerde op de bewoording.
Nou ben ik geen db guru, maar ik zie niet in waarom er bij een dergelijke query geen index gebruikt kan worden eigenlijk... Hij moet @langID en NULL opzoeken, en die NULL velden kunnen vervolgens worden gefiltered aan de hand van de waarde van @langID. Fair enough, aparte queries is waarschijnlijk optimaler, maar dat dit meteen al een index bypassed?
Nulls zitten vaak niet in een index.

Who is John Galt?


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

.oisyn schreef op maandag 11 februari 2008 @ 13:03:
[...]

Just out of interest, is jouw query beter dan de mijne waar de OR in staat? En zo ja, waarom?
Nee, SQL Server optimalizeert beiden weg tot een simpele index scan waarbij de functions irrelevant zijn voor performance.

Professionele website nodig?


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

justmental schreef op maandag 11 februari 2008 @ 13:10:
Nulls zitten vaak niet in een index.
Bij mij regelmatig eigenlijk in optionele foreign keys?

Professionele website nodig?


  • siroki
  • Registratie: Oktober 2006
  • Laatst online: 18-10 10:58
Peoples,

De oplossing met ISNULL(...,'') werkt prima. Bedankt hiervoor!

[ Voor 119% gewijzigd door siroki op 11-02-2008 13:29 ]


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
justmental schreef op maandag 11 februari 2008 @ 13:10:
Nulls zitten vaak niet in een index.
Volgens mij gaan die in een NULL bitmap? En is dus prima te indexen?

[ Voor 6% gewijzigd door RobIII op 11-02-2008 13:24 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


  • justmental
  • Registratie: April 2000
  • Niet online

justmental

my heart, the beat

curry684 schreef op maandag 11 februari 2008 @ 13:12:
Bij mij regelmatig eigenlijk in optionele foreign keys?
RobIII schreef op maandag 11 februari 2008 @ 13:22:
Volgens mij gaan die in een NULL bitmap?
Het kan wel, maar vaak zitten ze niet in de normale b-tree's.
In ieder geval is het vaak handig om er anders mee te optimaliseren, alleen al om het geval dat ze meestal een hele andere frequentie van voorkomen hebben dan een 'gewone' waarde.

Who is John Galt?


  • EfBe
  • Registratie: Januari 2000
  • Niet online
.oisyn schreef op maandag 11 februari 2008 @ 13:03:
[...]

Just out of interest, is jouw query beter dan de mijne waar de OR in staat? En zo ja, waarom?
Niet per-se beter, ik had jouw query niet goed bekeken, maar COALESCE is een native SQL statement en daardoor makkelijker intern te optimaliseren in de engine. Een OR query is dat niet (SQL is een geinterpreteerde taal nl. ;))

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


Verwijderd

EfBe schreef op maandag 11 februari 2008 @ 12:57:
select * from table where COALESCE(LangID, -1) == COALESCE(@LangID, -1)
Performance? En recompile inwisselen voor een table-scan... dan liever een recompile.

Edit> Volgens mij krijg je zelfs in 2005 geen recompile...

[ Voor 10% gewijzigd door Verwijderd op 11-02-2008 19:30 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

En waar haal je die table scan vandaan? Op een LangId zet je een index (foreign key ole) en dan krijg je in beide gevallen een (non)clustered index scan. Ik heb ze in SQL2k5 getest en allebei gaven hetzelfde execution plan.

Professionele website nodig?


  • EfBe
  • Registratie: Januari 2000
  • Niet online
Verwijderd schreef op maandag 11 februari 2008 @ 18:36:
[...]
Performance? En recompile inwisselen voor een table-scan... dan liever een recompile.
Edit> Volgens mij krijg je zelfs in 2005 geen recompile...
Een IF statement leidt vaak tot een recompile, omdat execution plans wijzigen omdat per setje input parameter values, het code-path in de routine anders is (de ene keer wel de true clause, de andere keer niet).

Ik zie ook de relevantie niet mbt de table-scan en de recompile, het zijn 2 totaal verschillende dingen. Als je met NULL values aan het kloten bent in stored procedures heb je COALESCE nodig of de OR truuk maar that's it, meer heb je niet. Een IF statement maakt het echt alleen maar trager.

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com

Pagina: 1