IFNULL() Equivalent in PostgreSQL - mysql

I am working on a project of migrating from MySQL to PostgreSQL, some function can't works well in PostgreSQL like IFNULL function. Some tutorials say that in PostgreSQL we can use NULLIF to handle it.
When I try I get an issue "argument of NOT must be type boolean, not type integer".
This is the simple SQL :
SELECT * FROM `tableA` WHERE not(nullif(columnA, 0));
How to solve it? Maybe some one can make an explain how can it works well. Thanks

NULLIF() is very different from IFNULL(). I think that what you want is COALESCE(), which will return the first non-NULL argument (it can have more than 2 arguments):
SELECT *
FROM table_a
WHERE NOT (COALESCE(column_a::boolean, false));
Reference: 9.17.2. COALESCE
Also, in Postgres you need to use true or false. 0 and 1 do not work for boolean literals. That's the reason that you get the error:
argument of NOT must be type boolean, not type integer
If column_a is an integer, then you have to CAST it to boolean. That's what column_a::boolean in the example above does. It is equivalent to CAST(column_a AS boolean).

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.

MySQL don't read second OR condition if the first one is true

I'm trying to make an SQL-statement where I get the parameters from c# code.
The problem is that some of the parameters can be 'null'. But in MySQL I can't properly read WHERE column=NULL and I can only do WHERE column IS NULL.
So I was trying to make the statement like this:
SELECT *
FROM table
WHERE column=param #(param given from C#)
OR column IS param
I thought this would work fine because MySQL shouldn't care about the second condition if the first one is already true (like Python). And it does work when param is null. But there's an error when param is a string because then MySQL reads: WHERE column IS 'string'.
Is there a way to solve this?
You seem to want <=>, the null-safe equality operator:
WHERE column <=> param
Basically, NULL <=> NULL is true, while NULL = NULL is undefined.
Note that you should be properly passing your parameter to the query, using a prepared statement. String 'null' is not the same thing as a null value.

case statement in MS Access query give error

I am using below query in Ms Access. And this gives me error Syntax error in your query expression CASE WHEN not ... . Can you please tell me what I am doing wrong? In Sql Server 2008 R2, the case statement runs correctly.
SELECT TableApron.RadButtonNo, TableApron.ShortName, QueryForNot1.InspectionDate, QueryForNot1.Findings, QueryForNot1.Status, QueryForNot1.Initials, TableApron.DeptName, TableApron.Lost, TableApron.InServelDate, TableApron.RemovedDate, TableApron.PrivateUserName, TableApron.PrivateUserEmail, TableApron.ApronType, TableApron.Manufacturer
FROM TableApron LEFT JOIN QueryForNot1 ON TableApron.RadButtonNo=QueryForNot1.RadButtonNoI
WHERE (((TableApron.Lost)="N" Or (TableApron.Lost)=[#Lost]) And ((TableApron.InServelDate) Is Null Or (TableApron.InServelDate) Between CDATE([#From]) And CDATE([#To]) Or (TableApron.InServelDate)<CDATE([#To])) And ((TableApron.RemovedDate) Is Null Or (TableApron.RemovedDate) Between CDATE([#From]) And CDATE([#To]) Or (TableApron.RemovedDate)>CDATE([#To])))
ORDER BY
CASE
WHEN not TableApron.RadButtonNo like '%[^0-9]%' THEN CONVERT(int,TableApron.RadButtonNo)
WHEN TableApron.RadButtonNo like '[0-9]%' THEN CONVERT(int,SUBSTRING(TableApron.RadButtonNo,1,PATINDEX('%[A-Z]%',TableApron.RadButtonNo)-1))
END,
CASE
WHEN not TableApron.RadButtonNo like '%[^0-9]%' THEN NULL
WHEN TableApron.RadButtonNo like '[0-9]%' THEN SUBSTRING(TableApron.RadButtonNo,PATINDEX('%[A-Z]%',TableApron.RadButtonNo),9000)
ELSE TableApron.RadButtonNo
END;
The CASE statement triggers the first reported error because it is not supported in Access SQL. Use IIf() instead as #Gustav suggested.
However then you will encounter additional errors because CONVERT, SUBSTRING, and PATINDEX are also not supported in Access SQL.
Instead of CONVERT, use CInt() to cast a value to Access Integer or CLng() for Long Integer. Or you could use Val() and let Access decide which numeric datatype to give you.
Instead of SUBSTRING, use Mid().
Instead of PATINDEX, use InStr().
Assuming those suggestions eliminate the syntax errors, you may still have an issue with the Like wildcard.
If you will be running the query from the query designer or elsewhere under DAO, Access expects * instead of % as the wildcard. % is the correct wild card only when the query is run from ADO/OleDb.

SSRS casting a parameter to decimal multi select

Im trying to cast a parameter in SSRS to a decimal. I have a in clause since its multi select. I can select 1 and it runs fine however if i select more than 1 it will say
"Incorrect syntax near the keyword 'as'."
I am casting my parameter in my where clause in my query statement.
WHERE LOAD_NO IN (CAST(#Load as DECIMAL))
I am confused as to why it would bring back the syntax error if I select more than one from list.
Thanks
I am confused as to why it would bring back the syntax error if I
select more than one from list.
Short answer
Because WHERE LOAD_NO IN (CAST(1,2,N as DECIMAL)) is not a valid T-SQL statement.
Long answer
When you use a multi-value parameter in a query, reporting services will generate different queries if your parameter contains 1 value, or multiple values.
Let's simplify your example to the following query:
SELECT * FROM TABLE WHERE LOAD_NO IN (#Load)
With only one value, the query will have the following format:
exec sp_executesql N'SELECT * FROM TABLE WHERE LOAD_NO IN (#Load)', N'#Load int', #Load=<YourValue>
It's a query with a parameter: #Load.
Now, with multiple values, the query will become
exec sp_executesql N'SELECT * FROM TABLE WHERE LOAD_NO IN (<YourValue1>, <YourValue2>,<YourValueN>)'
The #Load parameter has been replaced by the list of values.
So now my advise will be to rethink the design of your query and treat #Load as a list of values.
We cannot provide you the best solution because it really depends on the data and only you have all the details but I could still throw some ideas.
On the top of my head I could think of:
Cast LOAD_NO instead, but the execution plan may loose the benefits of indexes if any.
In most cases, using a IF EXISTS when possible instead of IN.
Use a subquery.
Do not hesitate to run a SQL Server Profiler to see the generated query if you have other issues.
I'm not sure what your data looks like, so I'm not sure if these options would help, but here's a couple suggestions:
Try putting the CAST on LOAD_NO instead:
WHERE CAST(LOAD_NO AS VARCHAR) IN (#Load)
Create a splitString function like the accepted post here (T-SQL split string) and access it in your WHERE clause:
WHERE LOAD_NO IN (SELECT CAST(val AS DECIMAL) FROM dbo.splitString(#Load, ','))

NVL2 function does not exist? mysql query

I'm trying to do some queries but I keep getting errors, now I'm thinking that there is something wrong with the mysql installation. Can anybody tell me if there is an error in this query?
SELECT settings.ID,
settings.name,
settings.description,
NVL2(userSettings.value, userSettings.value, settings.default)
FROM settings
LEFT OUTER JOIN userSettings ON (settings.ID = userSettings.settingID)
The error I get says the function databaseX.NVL2 does not exist
I recommend staying away from vendor specific functions when a ANSI standard equivalent alternative is available. NVL and IFNULL for example can (often) be replaced with COALESCE.
You can also use CASE WHEN, which means a lot more typing on the downside, but the upside is that people with background in SQL Server for example won't have to deal with Oracles DECODE() or NVL or NVL2, because the logic is right there in the code.
That's probably because NVL2 is an Oracle function, not a MySQL function. I believe the function you are looking for in MySQL would be COALESCE()
As #Eric Petroelje mentioned NVL2() is Oracle function, not MySQL. However MySQL has its own equivalent that can be used in this case: IFNULL():
SELECT ... IFNULL(userSettings.value, settings.default) ...
After several try&error probes, I found this method to emulate Oracle's NVL2 function. It's not very elegant, but it works
SELECT IF(LENGTH(ISNULL(FieldName, '')) > 0, 'Not NULL Value', 'Null Value') FROM TableName
I think this can help you
IF(expr1,expr2,expr3)
If expr1 is TRUE (expr1 <> 0 and expr1 <> NULL) then IF() returns expr2; otherwise it returns expr3. IF() returns a numeric or string value, depending on the context in which it is used.
Alternatively you can substitute NVL2 to:
IF (userSettings.value IS NULL, userSettings.value, settings.default)