New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Database\Table\Selection::where and NOT IN construct #667
Comments
Is there any workaround? |
Well, it's mysql thing. If you dont want to restrict the seleciton, don't call where condition.
|
By saying it's mysql thing, you mean in other databases this works well? Either way the behavior of this for mysql has big WTF factor, especially when using subqueries (which are optimized internally by NDB for MySql - and therefore won't work, while they would have worked if left unoptimized). Is the solution using special constant really so unacceptable? I think it would solve most problems for now, and perhaps later mysql comes with a possibility how to resolve this in cleaner way... |
Tohle je celkem známý problém, viz http://php.vrana.cz/operator-in-s-prazdnou-mnozinou.php#d-8096. Teoreticky workaround by existovat mohl. |
Srr, you are right, it's not only mysql problem, it's also in postgre. Only workaround which I know is to pass an magic value, which can't be present. Such |
Alternatively, it is also possible to use subquery such as |
The trick is that
I'm sure on PostgreSQL only... |
Wow! Works in MySQL too. I'm not sure if nette should add COALESCE automatically. |
This is a better solution than subquery, because you do not have to care about subquery return type. But when I take a look at Maybe I'm missing something, I'm a Nette\Database amateur. |
@hrach What do you think milo@65f05ee? |
The COALESCE is good idea, but in presented form it can be used only when the left side of the IN construct is not NULL. You can e.g. have
... where
However all this relates to ANSI NULLS being enabled, but some RDBMS allow to disable it... |
Well, I would avoid stripping condition and parameter analysis. There is no need to do it.
|
@hrach You didn't address the issue I presented at all. In your example, you work with primary key (userId) which you expect to be always non-NULL. If you consider cases with column that can contain NULL (or more generally an expression that evaluates to NULL) , you will realize COALESCE changes the behavior (if ANSI NULLS are enabled). My PHP example was merely meant to illustrate what i mean by |
Duplicit IN: see https://github.com/nette/nette/blob/master/Nette/Database/Table/SqlBuilder.php#L181 Oh, I get it now, maybe you should try to express you thoughts better :D Just write |
Ok, you were right about the duplicate IN, my bad. As for the actual problem we are discussing, I am glad you got it now, but I am afraid solution of @milo is also not respecting ANSI NULLS behavior for operand left of the IN operator. I am afraid replacing the condition with boolean is not the way because of this, as only the database knows what the left operand will evaluate to (whether it will be NULL or something else) and therefore PHP can't resolve it this way. What we need is to find a condition that could be used for empty list of values in combination with NOT IN and would work preferably for both ANSI NULLS enabled or disabled. Solution with COALESCE (when extended by check for NULL) might work for ANSI NULLS enabled, but what if they are disabled? So far I am inclined to solution with the special constant, but if there was another solution without described negative side effects, I would prefer that one. |
From my point of view I would not deal with empty array as "NULL" in "IN". If you want to filter by NULL, you would use "array(NULL)". |
@hrach I am not sure if you wanted to react on me in your last comment. In case you did, you probably missed the point again, in which case I suggest we discuss the matter in czech. |
Maybe I found the solution. For empty arrays, following replacement would occur:
Or did I miss something? |
Souhlas s češtinou :-) Vše je o situacích:
A celá naše diskuze je o tom, že se snažíme opravit SQL chování (syntax error) pro "prázdnou množinu", tedy případ 1 a 2. Myslím, že 1. by mělo být vždy |
@tomaswindsor: @milo solution is right, because it no longer solve 1st / 2nd as 3rd / 4th expression - which is the cutting edge. |
Máš pravdu. Z nějakého důvodu jsem měl za to, že když je expr |
I made a pull request #869. If you agree, we can continue discuss there. |
Database: SqlBuilder::addWhere() consider NOT [Closes #667]
…efs nette#667] Removed old behavior, which could produce malformed SQL query. Condition must have parentheses around all expressions with empty array.
Database: implemented correct support for empty array NOT operator [Refs #667]
…efs nette/nette#667] Removed old behavior, which could produce malformed SQL query. Condition must have parentheses around all expressions with empty array.
Currently, when using
$db->table('book')->where('NOT id', array())
or$db->table('book')->where('id NOT', array())
it will result in querySELECT * FROM book WHERE NOT ID IN (NULL)
orSELECT * FROM book WHERE ID NOT IN (NULL)
which will both return no rows because of special behavior ofNULL
. Same problem occurs for MySQL subqueries in$db->table('book')->where('NOT id', $subQuery)
, because Nette\Database performs optimization and replaces the actual subquery with its result, and if this result is empty, it will use(NULL)
.Solution could be replacing the
(NULL)
with some kind of query that returns an empty result (no idea about that one). Alternatively instead of empty list, we could use list containing special unique value, e.g.WHERE NOT ID IN ('~~NDB~NO~VALUES~~')
. Solution with simply removing whole condition in case ofNOT
is insufficient becauseNULL
can appear also on the left side of theIN
operator, and removing whole condition would then cause different behavior - imagine$db->table('book')->where('NOT NULL', array())
- I know this example doesn't look to be of much use, but keep in mind thatNULL
can be result of some sql function used in the condition as well...The text was updated successfully, but these errors were encountered: