Dynamic Values in 'IN' operator - mysql

I have a select statement in which the WHERE clause's IN operator. The query works properly as long as some values are passed to question mark (passed from java program). But when there are no values passed, I get a syntax error.
select
this_.categoryAddressMapId as category1_1_0_,
this_.categoryId as categoryId1_0_,
this_.addressId as addressId1_0_
from
icapcheckmyphotos.category_address_map this_ <br>
where
this_.addressId in (
?
)
When there are no parameters passed, I need null set. Please suggest how to modify the where clause. Thanks in advance

Modify your java program. Your choices are to not run the query if there are no addressIds, or ensure that it passes at least one value. If addressId is an integer field, pass -1 or something like that. Personally, I like the first option but it depends on your requirements.

how about doing sometiong like
where (? is null) OR this_.addressId in ( ? )
you may need to add some special treatment to the first part of the OR if your columns does accept NULLS

//pseudo code
...
WHERE 1
if(!null) {
AND this_.addressId in ('stuff')
}

Related

how to check if a column has truthy value using laravel's eloquent

Suppose I have Post model that has is_verified column with smallint datatype, how can I get all records that is verified? One thing to do this is using this:
Post::where('is_verified', true)->get();
The code above will produce the following query:
select * from `posts` where `posts`.`is_verified` = true
... which will get me all verified Post records; in note that is_verified on all existing records is either 0 or 1.
However, after I get myself curious and try to manually change some is_verified's record value from 1 to another truthy number e.g. 2, the above eloquent query didn't work as expected anymore: records with is_verified value of 2 didn't get retrieved.
I tried to execute the sql query directly from HeidiSQL as well, but it was just the same. Then I tried to change the = in the sql query to is, and now it's working as expected i.e. all records with truthy is_verified get retrieved:
select * from `posts` where `posts`.`is_verified` is true
So my questions are:
Does the above behaviour is correct and expected?
How can I execute the last sql query in eloquent? One thing I can think of is where('is_verified', '!=', 0) but that feels weird in terms of readability especially when the query is pretty long and a bit complicated
As I stated before, the is_verified column is a smallint. Does this affects the behaviour? Because this conversation here states that boolean column datatype is typically tinyint, not smallint.
And that's it. Thank you in advance!
It is not the correct way to handle boolean values, you shouldn't save boolean columns as smallint, you can use the explicit boolean column type as described in the documentation.
Once you setup the boolean field correctly the logic you have in place will work. So Post::where('is_verified', true)->get(); will return the expected results.
Yes, the problem is the smallint column type, if you put tinyint it also should work like the boolean column. You can read more about the differences here.
After doing some deeper digging, I would like to write down the things I've found:
I have updated my mysql to the newest version as of now (v8) and boolean datatype defined in migration results in tinyint(1) in the db. This is happening turns out because in mysql bool or boolean are actually just the synonyms of tinyint(1), so that was a totally normal behaviour, not due to lower-version issues.
I found #dz0nika answer that states that smallint and tinyint results in different behaviour in the query to be quite incorrect. The two datatypes simply differ in terms of byte-size while storing integer value.
As of mysql documentation, it is stated that:
A value of zero is considered false. Nonzero values are considered true.
But also that:
However, the values TRUE and FALSE are merely aliases for 1 and 0, respectively.
Meaning that:
select * from `posts` where `posts`.`is_verified` = true;
Is the same as
select * from `posts` where `posts`.`is_verified` = 1;
Thus the query will only get Post records with is_verified value of 1.
To get Post records with truthy is_verified value, wether 1, or 2, or 3, etc; use is instead of = in the query:
select * from `posts` where `posts`.`is_verified` is true;
You can read more about these informations here and here (look for the "boolean" part)
So, how about the eloquent query? How can we get Post with truthy is_verified using eloquent?
I still don't know what's best. But instead of using where('is_verified', '!=', 0) as I stated in my question, I believe it's better to use whereRaw() instead:
Post::whereRaw('posts.is_verified is true')->get();
If you found this information to be quite missing or incorrect, please kindly reply. Your opinion is much appreciated.

Select NULL as column using JOOQ

I'm trying to select NULL as a column in my query using JOOQ, so basically something like this:
SELECT name, NULL as 'someColumn' FROM someTable;
I need to do this, because the result needs to include someColumn (as part of a data standard), but we do not have this information in our database. This works fine in plain SQL, but I'm struggling to reproduce this using JOOQ.
Does anyone know how to do this in a query of this form?
context.select(
SOMETABLE.NAME,
... // Other columns here
DSL.NULL.as("someColumn") // <-- This doesn't exist
)
You can use an inline value
DSL.inline(null)
Depending on your database dialect or query usage, you may need to add a data type to that value, e.g.
DSL.inline(null, SQLDataType.VARCHAR)

Simple query condition in sql

I have a Query - - < This Is a valid Query >
'SELECT *
FROM MyTable
WHERE city= ?
ORDER BY name ' [Keyname]
I am using this queried condition :: i am passing the Keyname as params from client to this sql query
This works & i get the required result BUT
If i pass nothing say null comes from client as param value for Keyname......... this query fails
how can i make the better query ... so that even if null comes ....
ORDER BY condition is satisfied
Or
R there other solution i need to look for
If so ... what is it ?
Hope i am clear
[EDIT]
CASE1:: for the url
http://54.218.73.244:7005/DescriptionSortedSearchRating/?Key=Pune
my told query satisfies::
But
http://54.218.73.244:7005/DescriptionSortedSearchRating/?Key=
my query fails, my sql query is expecting a Key for http://54.218.73.244:7005/DescriptionSortedSearchRating/ ..... if i pass nothing my query dosent get me a result..
.
what i am trying to see is even if i get nothing as key ORDER BY condition must be met ...
IF I PASS A KEY VALUE
IF I DONT PASS A KEY VALUE
You can clearly see i am not able to fetch results from database (Empty JSON)
This question doesn't have anything to do with MySQL. This is 100% your high level language. The null value the [Keyname] has is a null value in the language you're using to create the string that will be the final query.
The simplest solution will be not to assign null to your [Keyname] variable but rather an empty string.
You may use this:
ORDER BY name CASE WHEN Keyname IS NULL THEN '' ELSE CONCAT(',', Keyname) END
I am not sure whether the syntax is fine or not. But what I expect here to append empty string when Keyname is null and to append the Keyname with a comma (,). Please try it.
Other option is using function ISNULL
ISNULL(Keyname, '');

Select query returns false result

eg:
Table : user
column : user_id (type is int)
SELECT * FROM user WHERE user_id = '10xyz'
is giving same result of
SELECT * FROM user WHERE user_id = '10'
The input value is not integer but not giving an error in this case.
The reason why you are getting the same result is because MySQL automatically removes the trailing characters from the string and implicitly converts it to integer.
SQLFiddle Demo
SQLFiddle Demo (updated)
If you don't want to change all your code, but you have your database queries all going through one or a few subs, you can change those to check for warnings after using a statement handle (e.g. if ( $sth->{mysql_warning_count} ) ...).
Or you can create a DBI subclass that does that automatically for you, promoting warnings to errors. If you do, many others have use for such a thing. There are configuration settings to give an error instead of a warning when updating or inserting something like '10xyz' into an integer field, but not anything broader than that, and dear Oracle considers it Not a Bug. Maybe MariaDB does (or could do) better?
datatype of user_id is in database is INT
that why it giving same output and not error

Subtracting the value from the last row using variable assignment in MySQL

According to the MySQL documentation:
As a general rule, you should never assign a value to a user variable and read the value within the same statement. You might get
the results you expect, but this is not guaranteed.
http://dev.mysql.com/doc/refman/5.6/en/user-variables.html
However, in the book High Perfomance MySQL there are a couple of examples of using this tactic to improve query performance anyway.
Is the following an anti-pattern and if so is there a better way to write the query while maintaining good performance?
set #last = null;
select tick, count-#last as delta, #last:=count from measurement;
For clarification, my goal is to find the difference between this row and the last. My table has a primary key on tick which is a datetime column.
Update:
After trying Shlomi's suggestion, I have reverted back to my original query. It turns out that using a case statement with aggregate functions produces unexpected behavior. See for example:
case when (#delta := (max(measurement.count) - #lastCount)) AND 0 then null
when (#lastCount := measurement.count) AND 0 then null
else #delta end
It appears that mysql evaluates the expressions that don't contain aggregate functions on a first pass through the results, and then evaluates the aggregate expressions on a second (grouping) pass. It appears to evaluate the case expression during or after that second pass and use the precalculated values from the first pass in that evaluation. The result is that the third line #delta is always the initial value of #delta (because assignment didn't happen until the grouping pass). I attempted to incorporate a group function into the line with #delta but couldn't get it to behave as expected. So I ultimately when back to my original query which didn't have this problem.
I would still love to hear any more suggestions about how to better handle a query like this.
Update 2:
Sorry for the lack of response on this question, I didn't have a chance to investigate further until now.
Using Shlomi's solution it looks like I had a problem because I was using a group by function when I read my #last variable but not when I set it. My code looked something like this:
CASE
WHEN (#delta := count - #last) IS NULL THEN NULL
WHEN (#last:= count ) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN #delta ELSE avg(count) END)
END AS delta
MySQL appears to process expressions that don't contain aggregate functions in a first pass and ones that do in a second pass. The strange thing in the code above is that even when cumulative evaluates to true MySQL must see the AVG aggregate function in the ELSE clause and decides to evaluate the whole inner CASE expression in the second pass. Since #delta is set in an expression without an aggregate function it seems to be getting set on the first pass and by the time the second pass happens MySQL is done evaluating the lines that set #delta and #last.
Ultimately I seem to have found a fix by including aggregate functions in the first expressions as well. Something like this:
CASE
WHEN (#delta := max(count) - #last) IS NULL THEN NULL
WHEN (#last:= max(count) ) IS NULL THEN NULL
ELSE (CASE WHEN cumulative THEN #delta ELSE avg(count) END)
END AS delta
My understanding of what MySQL is doing is purely based on testing and conjecture since I didn't read the source code, but hopefully this will help others who might run into similar problems.
I am going to accept Shlomi's answer because it really is a good solution. Just be careful how you use aggregate functions.
I've researched this issue in depth, and wrote a few improvements on the above.
I offer a solution in this post, which uses functions whose order can be expected. Also consider my talk last year.
Constructs such as CASE and functions such as COALESCE have known underlying behavior (at least until this is changed, right?).
For example, a CASE clause inspects the WHEN conditions one by one, by order of definition.
Consider a rewrite of the original query:
select
tick,
CASE
WHEN (#delta := count-#last) IS NULL THEN NULL
WHEN (#last:=count ) IS NULL THEN NULL
ELSE #delta
END AS delta
from
measurement,
(select #last := 0) s_init
;
The CASE clause has three WHEN conditions. It executes them by order until it meets the first that succeeds. I've written them such that the first two will always fail. It therefore executes the first, then turns to execute the second, then finally returns the third. Always.
I thus overcome the problem of expecting order of evaluation, which is a real and true problem, mostly evident when you start adding more complex clauses such as GROUP BY, DISTINCT, ORDER BY and such.
As a final note, my solution differs from yours in the first row on the result set -- with yours' it returns NULL, with mine it returns the delta between 0 and count. Had I used NULL I would have needed to change the WHEN conditions in some other way -- making sure they would fail on NULL values.