ORACLE: "Missing right parenthesis" error when using variables - sql

I have a very long Oracle SQL script that filters for article numbers in multiple places, i.e.:
[...]
where article_nr = 12345
[...]
To avoid adjusting 20 lines of code manually when changing the article, I introduced variables, i.e.:
define article_1 = 12345
[...]
where article_nr = &&article_1
[...]
Now, however, I get an error saying that it's "missing right parenthesis". I did not touch anything regarding a parenthesis, just replaced the 12345 by the variable.
Do I have to escape the "&&" somehow?
Sorry for not posting the full code, but its multiple nested selects.
Thanks
EDIT (Working example):
This works:
select * from stores
where
(opening_date >= '21.11.2016')
;
This DOESN'T works (either with one or with two "&"):
define opening = '21.11.2016'
select * from stores
where
(opening_date >= &&opening)
;
==> "missing right parenthesis"

Numeric literals do not require quote marks ...
where article_nr = 12345
but date (and string) literals do ...
(opening_date >= '21.11.2016')
The same rules apply for substitution variables. Numeric assignment:
where article_nr = &&article_1
Date assignment:
(opening_date >= '&&opening')
As others have commented, it's good practice to explicitly cast dates:
(opening_date >= to_date('&&opening', 'dd.mm.yyyy'))

Related

SQL overlap statement

I'm trying to do overlap in SQL (using postgres) but receive an syntax error. And i do not know why I'm getting error and whats wrong with my SQL Statement
Error text
[42601] ERROR: syntax error at or near "[" Position: 296
SQL Statement
SELECT *,
ARRAY_AGG("reserve"."state_id" ) AS "states" FROM "orders_order"
JOIN "reserve" ON ("order"."id" = "reserve"."order_id")
GROUP BY "order"."id"
HAVING (NOT (ARRAY_AGG("reserve"."state_id" )&& ['test']::varchar(255)[]))
As documented in the manual there are two ways to specify an array:
First with the array keyword:
array['test']
or as a string enclosed with curly braces:
'{test}'::text[]
In the second case the casting might or might not be needed depending on the context on where it's used.
There is no need to cast it to a varchar(255)[] array. text[] will do just fine - especially when comparing it to the result of an array_agg() which returns text[] as well.

ORA-01797: this operator must be followed by ANY or ALL error

While I am executing the query,
select *
from file_log f
where F.DCP_SRCE_FILENM_FK in ('ABC','DEF') and
F.TRANS_DT>=to_date('08/25/2017','mm/dd/yyyy') and
F.TRANS_DT<=('08/30/2017','mm/dd/yyyy')
am getting the following error:
ORA-01797: this operator must be followed by ANY or ALL.
Could you all please help me in writing the proper query so that this error would go?
Just use the date keyword and ISO constants:
select *
from file_log f
where F.DCP_SRCE_FILENM_FK in ('ABC','DEF') and
F.TRANS_DT >= date '2017-08-25' and
F.TRANS_DT <= date '2017-08-30';
You are getting the error because the second constant is missing to_date(). But you might as well use the proper syntax for a date constant.
You are missing TO_DATE:
select *
from file_log f
where F.DCP_SRCE_FILENM_FK in ('ABC','DEF') and
F.TRANS_DT>=to_date('08/25/2017','mm/dd/yyyy') and
F.TRANS_DT<=TO_DATE('08/30/2017','mm/dd/yyyy') -- Missing on this line
Why it is throwing that exception:
The SQL parser cannot discern that you intended to use a TO_DATE function and assumes the final line is trying to compare F.TRANS_DT with one (ANY) or both (ALL) the values ('08/30/2017','mm/dd/yyyy') so is assuming the query should have the syntax:
select *
from file_log f
where F.DCP_SRCE_FILENM_FK in ('ABC','DEF') and
F.TRANS_DT>=to_date('08/25/2017','mm/dd/yyyy') and
F.TRANS_DT<= ANY ('08/30/2017','mm/dd/yyyy')
Which is a syntactically valid query. It would not, however, execute as trying to parse the F.TRANS_DT <= 'mm/dd/yyyy' comparison will result in trying to implicitly convert the string on the right-hand side to a date which is almost certain to fail with ORA-01858: a non-numeric character was found where a numeric was expected. But the SQL parser has done its best to suggest what is missing to make the query valid.
For those who end up searching for ORA-01797 error:
This error appears when right side of a logical operator ( =, !=, >, <, <=, >= ) contains multiple values.
Possible solutions:
Make sure right hand side of the logical operator contains a single value.
Handle multiple values by using IN instead of ( = ) and NOT IN instead of ( != )
Handle multiple values by using ALL, ANY or SOME as documented.

Why is the output different in SQL Server and same in Oracle?

Why is the output of below two queries is different in SQL Server and same in Oracle ?
SELECT 20.0/-2.0/5
SELECT 20/(-2.0)/5
I'm not agree with your statement that the output should be the same.
If you ask me what 20/-2/5 much output, I will answer you that it could output -2 or -50, depends on implementation details.
In Oracle, the only thing you know is that operators '*' and '/' are evaluated before '+' and '-'. But that's all. I don't find any documentation on the priority gives to operator '*' and '/' between themselves.
Since the two query gives -2, you can assume that the parenthesis are left over, and the calculation is made from left to right.
In SQL Server, the docs specified that
When two operators in an expression have the same operator precedence
level, they are evaluated left to right based on their position in the
expression.
So this computation is conform to the specs :
20/2/5 = (20/2)/5 = 2
Now add the minus sign
20/-2/5 = 20/(-2/5) = -50
Add parenthesis again
20/(-2)/5 = (20/-2)/5 = -2
So not only the parenthesis change the order, but the minus sign too.
In fact, the result should be considered as Undefined, and you can't rely on it.
Add some parenthesis for having a well defined result and prevent headache.

Assistance with SQL View

I'm having a little trouble with this sql view.
CREATE OR REPLACE VIEW view_themed_booking AS
SELECT tb.*,
CASE
WHEN (tb.themed_party_size % 2) = 0 THEN
(tb.themed_party_size-2)/2
ELSE ((tb.themed_party_size-2)/2) + 0.5
END themed_tables
FROM themed_booking tb;
Can anyone help me here? I'm trying to add a column to the end of the view that the natural number result of (S-2)/2 where S is the themed_party_size.
When i say natural number result i mean like round up the answers that end in .5 so if S=7 the answer would be 3 and not 2.5.
The error I get when I try and run the above code is
Error starting at line 1 in command:
CREATE OR REPLACE VIEW view_themed_booking AS
SELECT tb.*,
CASE WHEN (tb.themed_party_size % 2) = 0
THEN (tb.themed_party_size-2)/2
ELSE ((tb.themed_party_size-2)/2) + 0.5
END themed_tables
FROM themed_booking tb
Error at Command Line:3 Column:34
Error report:
SQL Error: ORA-00911: invalid character
00911. 00000 - "invalid character"
*Cause: identifiers may not start with any ASCII character other than
letters and numbers. $#_ are also allowed after the first
character. Identifiers enclosed by doublequotes may contain
any character other than a doublequote. Alternative quotes
(q'#...#') cannot use spaces, tabs, or carriage returns as
delimiters. For all other contexts, consult the SQL Language
Reference Manual.
*Action:
If it makes a difference I am using sqldeveloper connected to an oracle server so I can use PL/SQL.
The error message is telling you what the problem is.
Look at Line:3 Column:34
It is an invalid character
CREATE OR REPLACE VIEW view_themed_booking AS
SELECT tb.*,
CASE WHEN (tb.themed_party_size % 2) = 0
^
My suspicion is that you are trying to use the modulo operator.
Since you are using oracle PL/SQL, you should use mod
Here is a reference Oracle/PLSQL: Mod Function
I think you can simplify with the CEIL() or ROUND() function:
CREATE OR REPLACE VIEW view_themed_booking AS
SELECT tb.*,
ROUND((tb.themed_party_size-2)/2) AS themed_tables
FROM themed_booking tb;
Not sure why you get that error. Perhaps it's the % operator that is not available in Oracle. This links suggests so: Fundamentals of PL/SQL. There seems to be a MOD() function though.

Does this behavior exist in all major databases?

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.