Jak radzić sobie z (może) wartościami null W PreparedStatement?

Twierdzenie jest

SELECT * FROM tableA WHERE x = ?

I parametr jest wstawiany przez Javę.sql.PreparedStatement "stmt"

stmt.setString(1, y); // y may be null

Jeśli y jest null, instrukcja nie zwraca wierszy w każdym przypadku, ponieważ {[4] } jest zawsze false (powinno być x IS NULL). Jednym z rozwiązań byłoby

SELECT * FROM tableA WHERE x = ? OR (x IS NULL AND ? IS NULL)

Ale potem muszę ustawić ten sam parametr dwa razy. Czy jest lepsze rozwiązanie?

Dzięki!
Author: aioobe, 2010-11-18

5 answers

Zawsze robiłam to tak, jak pokazałeś w swoim pytaniu. Ustawienie tego samego parametru dwa razy nie jest takim wielkim trudem, prawda?

SELECT * FROM tableA WHERE x = ? OR (x IS NULL AND ? IS NULL);
 37
Author: Paul Tomblin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 13:34:25

Istnieje dość nieznany operator ANSI-SQL IS DISTINCT FROM, który obsługuje wartości NULL. Można go używać w ten sposób:

SELECT * FROM tableA WHERE x NOT IS DISTINCT FROM ?

Więc trzeba ustawić tylko jeden parametr. Niestety nie jest to obsługiwane przez MS SQL Server (2008).

Innym rozwiązaniem może być, jeśli istnieje wartość, która jest i nie będzie nigdy używana ('XXX'):

SELECT * FROM tableA WHERE COALESCE(x, 'XXX') = COALESCE(?, 'XXX')
 10
Author: Zeemee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-28 08:57:17

Użyłbym tylko 2 różnych wyrażeń:

Wypowiedź 1:

SELECT * FROM tableA WHERE x is NULL

Wypowiedź 2:

SELECT * FROM tableA WHERE x = ?

Możesz sprawdzić swoją zmienną i zbudować odpowiednie polecenie w zależności od warunku. Myślę, że to sprawia, że kod jest znacznie jaśniejszy i łatwiejszy do zrozumienia.

EDIT Przy okazji, dlaczego nie skorzystać z procedur przechowywanych? Następnie możesz obsłużyć całą tę logikę NULL w SP i możesz uprościć rzeczy na wywołaniu front end.

 6
Author: dcp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 13:27:49

Jeśli używasz np. mysql to prawdopodobnie możesz zrobić coś w stylu:

select * from mytable where ifnull(mycolumn,'') = ?;

Then yo could do:

stmt.setString(1, foo == null ? "" : foo);
Musisz sprawdzić swój plan wyjaśnień, aby zobaczyć, czy poprawia to Twoje wyniki. Oznaczałoby to jednak, że pusty łańcuch jest równy null, więc nie jest przyznany, że pasuje do Twoich potrzeb.
 0
Author: Knubo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-18 14:08:56

W Oracle 11g robię to w ten sposób, ponieważ x = null technicznie ocenia się na UNKNOWN:

WHERE (x IS NULL AND ? IS NULL)
    OR NOT LNNVL(x = ?)

Wyrażenie przed OR zajmuje się zrównaniem NULL Z NULL, następnie wyrażenie po zajmuje się wszystkimi innymi możliwościami. LNNVL zmiany UNKNOWN na TRUE, TRUE do FALSE i FALSE do TRUE, co jest dokładnym przeciwieństwem tego, czego chcemy, stąd NOT.

Przyjęte rozwiązanie nie działało dla mnie w Oracle w niektórych przypadkach, gdy było częścią większego wyrażenie, obejmujące NOT.

 0
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-05 20:02:59