Does this behavior exist in all major databases? - sql

mysql> select 0.121='0.121';
+---------------+
| 0.121='0.121' |
+---------------+
| 1 |
+---------------+
Does it hold for other database that number='number' is true?

First of all: most databases are using localized number formats. So turning a number into a string will most probably not always be the same as your hard-coded string.
Then: you will get problems with the sql syntax you use. See my experiments with oracle bellow.
In Oracle you always need a FROM clause (except they changed this in version 10).
select 0.121='0.121' from sys.dual
In Oracle, you can't have an expression like this in the select clause.
You need a case statement:
select case when 0.121 = '0.121' then 1 else 0 end as xy
from sys.dual
Then you get an error that it is no number. To fix this, convert it:
select case when To_Char(0.121) = '0.121' then 1 else 0 end as xy
from sys.dual
this will return 0! Because, on my machine, 0.121 is converted to the string ".121". These are Swiss settings. If I had German settings, it would be ",121" (note the comma).
So to finally answer the question: No.

Even if it does. What does this help you ?
I would never, ever, make this assumption anyway. You always need to convert both operands to the same type so that, at least, you know what you are comparing.

Most of the reputable databases will do an implicit conversion for this type of query. There may be published rules for implicit conversions on a particular system - you'd have to look at the vendor coumentation to find out what implicit conversions are done on your system.
For instance,
here's an official reference from Microsoft for SQL Server 2000, and
here's a blog entry on SQL Server implicit conversions.

No.
I don't know why Stackoverflow requires me to enter more than 3 characters in answer to this question.

Postgresql is a little more strict than mysql about type conversion, and does not let you implicitly cast/convert between numbers and strings. This is sane behaviour, and it is getting slightly more strict with newer versions. Some examples, from Postgres 8.4:
db=# select 0.112::float = '0.112'::text;
ERROR: operator does not exist: double precision = text
LINE 1: select 0.112::float = '0.112'::text;
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
db=# select 0.112 = ('0.1' || '12');
ERROR: operator does not exist: numeric = text
LINE 1: select 0.112 = ('0.1' || '12');
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
db=# select 0.112 = ('0.1' || '12')::float; -- explicit cast
t
However, this example (the original question) works:
db=# select 0.122 = '0.122';
t
This is a little surprising (or misleading), given the above. But it has to do with how the query is parsed: when it sees an (unqualified) '0.122' literal, the parser does not necessarily assumes it is of TEXT type, but assigns instead a preliminary "unknown" type; its final type is deduced later by some heuristics.
Anyway, it's bad practice to rely on this, as mentioned by others.

Related

Operator does not exist date=integer when filtering for dates in postgreSQL

I have a large data set on dbeaver (postgreSQL), and I am trying to filter for the following:
select * from raw_data_file where data_file_group_id = 2592 and dl_date = 2022-06-15
However, I am getting an error for the dl_date part of the filter- any suggestions?
SQL Error [42883]: ERROR: operator does not exist: date = integer¶ Hint: No operator matches the given name and argument types. You might need to add explicit type casts.¶ Position: 74
Stu's comment is correct. Use quotes, single quotes, otherwise the subexpression looks like a couple of subtractions.

SQL query problem in WHERE clause, this returns all that start with

I've written the following SQL query to return all sites having "id" equal to 2.
SELECT * FROM `sites` WHERE id = '2'
And it works well. The problem is that even if I add some characters after "2" like this :
SELECT * FROM `sites` WHERE id = '2etyupp-7852-trG78'
It returns the same results as above.
How to avoid this ? that's to say return none on the second query ?
Thanks
The reason is that you are mixing types:
where id = '2'
------^ number
-----------^ string
What is a SQL engine supposed to do? Well, the standard approach is to convert the string to a number. So this is run as:
where id = 2
What happens when the string is not a number? In most databases, you get a type conversion error. However, MySQL does implicit conversion, converting the leading digits to a number. Hence, your second string just comes 2.
From this, I hope you learn not to mix data types. Compare numbers to numbers. Compare strings to strings.

Search Through All Between Values SQL

I have data following data structure..
_ID _BEGIN _END
7003 99210 99217
7003 10225 10324
7003 111111
I want to look through every _BEGIN and _END and return all rows where the input value is between the range of values including the values themselves (i.e. if 10324 is the input, row 2 would be returned)
I have tried this filter but it does not work..
where #theInput between a._BEGIN and a._END
--THIS WORKS
where convert(char(7),'10400') >= convert(char(7),a._BEGIN)
--BUT ADDING THIS BREAKS AND RETURNS NOTHING
AND convert(char(7),'10400') < convert(char(7),a._END)
Less than < and greater than > operators work on xCHAR data types without any syntactical error, but it may go semantically wrong. Look at examples:
1 - SELECT 'ab' BETWEEN 'aa' AND 'ac' # returns TRUE
2 - SELECT '2' BETWEEN '1' AND '10' # returns FALSE
Character 2 as being stored in a xCHAR type has greater value than 1xxxxx
So you should CAST types here. [Exampled on MySQL - For standard compatibility change UNSIGNED to INTEGER]
WHERE CAST(#theInput as UNSIGNED)
BETWEEN CAST(a._BEGIN as UNSIGNED) AND CAST(a._END as UNSIGNED)
You'd better change the types of columns to avoid ambiguity for later use.
This would be the obvious answer...
SELECT *
FROM <YOUR_TABLE_NAME> a
WHERE #theInput between a._BEGIN and a._END
If the data is string (assuming here as we don't know what DB) You could add this.
Declare #searchArg VARCHAR(30) = CAST(#theInput as VARCHAR(30));
SELECT *
FROM <YOUR_TABLE_NAME> a
WHERE #searchArg between a._BEGIN and a._END
If you care about performance and you've got a lot of data and indexes you won't want to include function calls on the column values.. you could in-line this conversion but this assures that your predicates are Sargable.
SELECT * FROM myTable
WHERE
(CAST(#theInput AS char) >= a._BEGIN AND #theInput < a.END);
I also saw several of the same type of questions:
SQL "between" not inclusive
MySQL "between" clause not inclusive?
When I do queries like this, I usually try one side with the greater/less than on either side and work from there. Maybe that can help. I'm very slow, but I do lots of trial and error.
Or, use Tony's convert.
I supposed you can convert them to anything appropriate for your program, numeric or text.
Also, see here, http://technet.microsoft.com/en-us/library/aa226054%28v=sql.80%29.aspx.
I am not convinced you cannot do your CAST in the SELECT.
Nick, here is a MySQL version from SO, MySQL "between" clause not inclusive?

PostgreSQL Concat 2 numbers gives me error

I'm trying to concat 2 numbers from two different columns, those are chain_code and shop_code.
I tried this:
SELECT CONCAT(`shop_code`, `shop_code`) AS myid FROM {table}
But I get an error:
ERROR: operator does not exist: ` integer
LINE 1: SELECT CONCAT(`shop_code`, `shop_code`) AS myid FROM...
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
I even tried to convert it to string but couldn't ... CONCAT(to_char(chain_code, '999')...) ... but it says there is no such a function called 'to_sting' (found on PostgreSQL Documentation)
First: do not use those dreaded backticks ` , that's invalid (standard) SQL.
To quote an identifier use double quotes: "shop_code", not `shop_code`
But as those identifiers don't need any quoting, just leave them out completely. In general you should avoid using quoted identifiers. They cause much more trouble than they are worth it.
For details on specifying SQL identifiers see the manual: http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
But concat() only works on text/varchar values, so you first need to convert/cast the integer values to varchar:
SELECT CONCAT(chain_code::text, shop_code::text) AS myid FROM...
but it says there is no such a function called 'to_sting'
Well, the function is to_char(), not to_sting().
Using to_char() is an alternative to the cast operator ::text but is a bit more complicated in this case:
SELECT CONCAT(to_char(chain_code,'999999'), to_char(shop_code, '999999')) AS myid FROM...
The problem with to_string() in this context is, that you need to specify a format mask that can deal with all possible values in that column. Using the cast operator is easier and just as good.
Update (thanks mu)
As mu is to short pointed out, concat doesn't actually need any cast or conversion:
SELECT CONCAT(chain_code, shop_code) AS myid FROM...
will work just fine.
Here is an SQLFiddle showing all possible solutions: http://sqlfiddle.com/#!15/2ab82/3

Querying on text values being casted into dates in postgresql

I was fiddling around with one of our databases earlier today and I was curious on how to do something in psql. Let's say I have a query like the following (with value1 being a text type in mytable):
SELECT * FROM mytable WHERE value1::date < '2013-10-24'::date;
This works fine if all the rows contain cast-able date strings. The second it finds a string that CAN NOT be casted into a date, an error is thrown like the following:
ERROR: invalid input syntax for type date: "C"
This makes sense and should happen. But is there a way to modify the above query so that if we come to a row where value1 would trigger this error that it would just move on, and skip over that row? I'm asking more out of curiosity than an actual need for an answer, and digging around on the web hasn't produced much (although, that could be do to the keywords I'm using, of course.)
You can use like-pattern or regex to pre-filter only value1s looking like dates:
SELECT * FROM mytable WHERE
value1 like '____-__-__'
and value1::date < '2013-10-24'::date;
SELECT * FROM mytable WHERE
value1 similar to '[1-2][0-9]{3}-[0-1][0-9]-[0-3][0-9]'
and value1::date < '2013-10-24'::date;
Here it is in SQLfiddle - http://sqlfiddle.com/#!1/06916/6
Technically we can't assume left-to-right evaluation order of the WHERE clauses, which means that in such a clause:
WHERE value1 ~ '^\d{4}-\d{2}-\d{2}$' AND value1::date < '2013-10-24'::date
the planner may decide to evaluate value1::date first and the execution will error out before testing the regexp. Should it estimate that the cast plus comparison is faster than the regexp test, it's a perfectly reasonable choice to make.
I don't think the current PostgreSQL code is sophisticated enough to do that specific rearrangement, but this problem is covered by the doc in Expression Evaluation Rules, and it recommends to use CASE to conditionally avoid the evaluation of problematic expressions.
Following this advice, the query would be like:
SELECT * FROM mytable WHERE
CASE WHEN value1 ~ '^\d{4}-\d{2}-\d{2}$'
THEN value1::date < '2013-10-24'::date
ELSE false
END;
Also if the content format seems to match a date but which happens to be invalid (e.g. 2013-01-32), the query will still fail. If this is a concern, you should encapsulate the cast in a function that traps the error:
create function cast_date(text) returns date as $$
begin
return $1::date;
exception when others then return null;
end; $$ language plpgsql;
and replace the test with cast_date(value1) < '2013-10-24'::date
May be this will work:
SELECT * FROM mytable WHERE value1 ~ '^\d{4}-\d{2}-\d{2}$' AND
value1::date < '2013-10-24'::date
regular expression will check if value1 is in needed format. and if it's not then cast to date shouldn't happen.