In query missing expressions of Oracle SQL Developer - oracle

SELECT b.*
FROM buses b,
bus_stations bs,
starts st,
stops_at sa
WHERE st.station_no = ( SELECT station_id
FROM bus_stations
WHERE station_name = "golden mile_Regina"
)
AND sa.station_no = ( SELECT station_id
FROM bus_stations
WHERE station_name = 'westmount_edmonton'
)
ORDER BY DATE;

You can't use double quotes with strings - use single ones, i.e.
WHERE station_name = 'golden mile_Regina'
By the way, are you sure of spelling & letter size? Is it really mixed case, with underscores? Just asking.
Furthermore, you're ordering by DATE - that won't work either, you can't use DATE as a column name (unless you enclose it into double quotes, but I certainly wouldn't recommend that). Have a look at the following example (stupid, yes - setting date to be a number, but I used it just to emphasize that DATE can't be used as a column name):
SQL> create table test (date number);
create table test (date number)
*
ERROR at line 1:
ORA-00904: : invalid identifier
Once you fix that, you'll get unexpected result as there are 4 tables in the FROM clause, but they aren't joined with one another, so that will be a nice Cartesian product.

Related

Missing parenthesis in oracle sql developer

Hello so i was coding a procedure for my database but i got stuck when i the compiler(Oracle SQL Developer) started telling me that
there is a missing right parenthesis
but there is no missing parenthesis as much as I observe.
Here is the procedure:
CREATE OR REPLACE PROCEDURE generer_listes_preferees (
p_id_user IN UTILISATEUR."id_user"%TYPE,
p_films OUT SYS_REFCURSOR
)
AS
-- Déclarer les variables locales
CURSOR c_films IS
SELECT *
FROM OBJET
WHERE "categorie_obj" LIKE 'Films' AND "id_objet" IN (
SELECT "id_objet"
FROM AVIS
WHERE "id_user" = p_id_user
ORDER BY "note" DESC, "date_avis" DESC
)
FETCH FIRST 10 ROWS ONLY;
BEGIN
-- Générer la liste de films préférés
OPEN p_films FOR SELECT * FROM TABLE(c_films);
END;
What could be the issue?
The procedure does not compile because the query is not valid. In particular, Oracle is looking for the closing parenthesis to finish the subquery, but it finds an unexpected ORDER BY clause instead:
SELECT *
FROM OBJET
WHERE "categorie_obj" LIKE 'Films' AND "id_objet" IN (
SELECT "id_objet"
FROM AVIS
WHERE "id_user" = p_id_user
ORDER BY "note" DESC, "date_avis" DESC
)
(Demo)
The error message could indeed be more useful, but the problem with incorrect code is that the parser can't really figure out your intentions.
Even if the ORDER BY clause was allowed, it wouldn't accomplish anything. The IN () operator is not sensitive to order. I guess you meant to order the main outer query.
It's also worth noting that "categorie_obj" LIKE 'Films' is the same as "categorie_obj" = 'Films'. Performance overhead (it has to parse the expression looking for wildcards) is for sure negligible, but I think it's more readable to just be explicit.
On a side note, I'd advise against double quoting identifiers. The only feature it provides is to hard-code the table/column case, so you're forced to type the quotes and the exact case every time since expressions WHERE categorie_obj or WHERE CATEGORIE_OBJ will no longer work.

ORACLE SUBQUERY NOT WORKING IN (IN CONDITION)

I need help
i have records 123,456,789 in rows when i am execute like
this one is working
select * from table1 where num1 in('123','456')
but when i am execute
select * from table1 where num1 in(select value from table2)
no resultset found - why?
Check the DataType varchare2 or Number
try
select * from table1 where num1 in(select to_char(value) from table2)
Storing comma separated values could be the cause of problem.
You can try using regexp_substr to split comma.
First and foremost, an important thing to remember: Do not store numbers in character datatypes. Use NUMBER or INTEGER. Secondly, always prefer VARCHAR2 datatype over CHAR if you wish to store characters > 1.
You said in one of your comments that num1 column is of type char(4). The problem with CHAR datatype is that If your string is 3 characters wide, it stores the record by adding extra 1 space character to make it 4 characters. VARCHAR2 only stores as many characters as you pass while inserting/updating and are not blank padded.
To verify that you may run select length(any_char_col) from t;
Coming to your problem, the IN condition is never satisfied because what's actually being compared is
WHERE 'abc ' = 'abc' - Note the extra space in left side operator.
To fix this, one good option is to pad the right side expression with as many spaces as required to do the right comparison.The function RPAD( string1, padded_length [, pad_string] ) could be used for this purpose.So, your query should look something like this.
select * from table1 where num1 IN (select rpad(value,4) from table2);
This will likely utilise an index on the column num1 if it exists.
The other one is to use RTRIM on LHS, which is only useful if there's a function based index on RTRIM(num1)
select * from table1 where RTRIM(num1) in(select value from table2);
So, the takeaway from all these examples is always use NUMBER types to store numbers and prefer VARCHAR2 over CHAR for strings.
See Demo to fully understand what's happening.
EDIT : It seems You are storing comma separated numbers.You could do something like this.
SELECT *
FROM table1 t1
WHERE EXISTS (
SELECT 1
FROM table2 t2
WHERE ',' ||t2.value|| ',' LIKE '%,' || rtrim(t1.num1) || ',%'
);
See Demo2
Storing comma separated values are bound to cause problems, better change it.
Let me tell you first,
You have stored values in table2 which is comma seperated.
So, how could you match your data with table1 and table2.
Its not Possible.
That's why you did not get any values in result set.
I found the Solution using string array
SELECT T.* FROM TABLE1 T,
(SELECT TRIM(VALUE)AS VAL FROM TABLE2)TABLE2
WHERE
TRIM(NUM1) IN (SELECT COLUMN_VALUE FROM TABLE(FUNC_GETSTRING_ARRAY(TABLE2.VAL)))
thanks

ORA-00936 with a substitution variable - error does not make sense

A super simple example of my script looks as follows:
-- Report Name: "Report_1"
col letters new_value p_letters
SELECT letters
FROM param_table
WHERE report_name = 'Report_1';
CREATE TABLE temp_table_1
(letter varchar2(1));
INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '&&p_letters' = '' OR letter IN (&&p_letters);
For some reason, our system has a table called param_table: users enter parameters through the UI, the parameters entered are written to param_table, and then my script pulls the user's parameters from param_table.
As far as I understand, the first SELECT statement selects the letters column from param_table and makes its values accessible in '&&p_letters'. In my INSERT INTO statement, when my WHERE clause looks like this...
WHERE letter IN (&&p_letters);
...and the user enters letters separated by single quotes, eg ('A', B', C'), the script runs fine. I want to make the parameter optional, so I adjusted the WHERE clause like this:
WHERE '&&p_letters' = '' OR letter IN (&&p_letters);
In my output file, I get the following error:
WHERE (('' = '') OR letter IN ()) *
ERROR at line ...:
ORA-00936: missing expression
The compiler has evaluated the substitution variable correctly as '', but I'm getting an error.
Any idea what I could be doing wrong here?
The ORA-00936 is because IN () is not valid - you're missing something inside that. It is that it is complaining about, not the '' = '' part, though the result of that is undefined. You can check both conditions:
SQL> select * from dual where '' = '';
no rows selected
SQL> select * from dual where dummy in ();
select * from dual where dummy in ()
*
ERROR at line 1:
ORA-00936: missing expression
If you set verify on you can see how the substitution is handled. For your original query you'd see:
old:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE letter IN (&&p_letters)
new:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE letter IN ('A','B','C')
3 rows inserted.
You can see that the post-substitution statement looks, and is, valid.
With your modified query you'd see:
old:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '&&p_letters' = '' OR letter IN (&&p_letters)
new:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE ''A','B','C'' = '' OR letter IN ('A','B','C')
which generates an ORA-00920 because of the messed-up single quotes in the first expression. With no value from letters you'd instead see:
old:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '&&p_letters' = '' OR letter IN (&&p_letters)
new:INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE '' = '' OR letter IN ()
which is the error you saw, ORA-00936.
I'd be tempted to do this with a collection type, either your own, or if you're comfortable with it then a built-in one:
INSERT INTO temp_table_1(letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE SYS.DBMS_DEBUG_VC2COLL(&&p_letters) IS EMPTY
OR letter MEMBER OF SYS.DBMS_DEBUG_VC2COLL(&&p_letters);
That works with your three comma-separated values, or null, since an empty collection is allowed. Read more about is empty and member of.
It would be better, of course, to not store comma-separated lists in a single column value anyway, and to change your data model so this kind of manipulation and reliance on client behaviour isn't necessary.
Assuming you're stuck with the data model, you could at least avoid the client reliance buy tokenizing the string (I'm using one common approach below) and looking for matches. However, you also need to account for either the report name not being in the table at all or the report existing with no letters value, both of which are handled by the max(letters) .. is null check - which makes it a bit ugly.
It's all in one statement though, with no need for a separate query to get the parameters and no need for substitution variables. (And there may be better ways to do it!)
INSERT INTO temp_table_1 (letter)
SELECT DISTINCT letter
FROM table_alphabet
WHERE (
SELECT MAX(letters)
FROM param_table
WHERE report_name = 'Report_2'
) IS NULL
OR letter IN (
SELECT TRIM(q'[']' FROM REGEXP_SUBSTR(letters, '[^,]', 1, LEVEL))
FROM param_table
WHERE report_name = 'Report_2'
CONNECT BY REGEXP_SUBSTR(letters, '[^,]', 1, level) IS NOT NULL
);

Oracle: ORA-01722: invalid number

I have a query which works nice when I run it inside sqlplus:
SQL> SELECT T_0.ID AS ATTR_1_, T_0_0.ID AS ATTR_2_,
CASE WHEN ( T_0.ID=1 AND ( T_0_0.ID=3 OR T_0_1.ID='val_1') )
THEN 'val_1' ELSE 'val_2' END AS TXT, T_0_1.ID,
CASE WHEN T_0.ID='boo' THEN 'boo' END AS EXTRA_FIELD
FROM TEST_TABLE T_0
INNER JOIN TEST_TABLE_2 T_0_0 ON ( T_0_0.ATTR=T_0.ID )
INNER JOIN TEST_TABLE_3 T_0_1 ON ( T_0_1.ID = T_0_0.ID )
WHERE ( ( T_0.ID=1 AND T_0_0.ID=3 )
OR T_0_1.ID=2 OR T_0_0.TXT='val_2');
no rows selected
Although, it returns nothing, it still works and does not result in error. However, when I do the same thing in Python, using bindings, I get this error message:
cx_Oracle.DatabaseError: ORA-01722: invalid number
This is how my query looks in Python, before I do cursor.execute:
SELECT T_0.ID AS ATTR_1_, T_0_0.ID AS ATTR_2_,
CASE WHEN ( T_0.ID=:TXT_ AND ( T_0_0.ID=:TXT__ OR T_0_1.ID=:TXT___ ) )
THEN :TXT___ ELSE :TXT____ END AS TXT, T_0_1.ID,
CASE WHEN T_0.ID=:EXTRA_FIELD THEN :EXTRA_FIELD END AS EXTRA_FIELD
FROM TEST_TABLE T_0
INNER JOIN TEST_TABLE_2 T_0_0 ON ( T_0_0.ATTR=T_0.ID )
INNER JOIN TEST_TABLE_3 T_0_1 ON ( T_0_1.ID = T_0_0.ID )
WHERE ( ( T_0.ID=:ID AND T_0_0.ID=:ID_ )
OR T_0_1.ID=:ID__ OR T_0_0.TXT=:TXT )
The query is just a string double-quoted "SELECT ..." . And this is how the dictionary with binding variables looks like:
OrderedDict([('TXT_', 1), ('TXT__', 3), ('TXT___', 'val_1'),
('TXT____', 'val_2'), ('EXTRA_FIELD', 'boo'), ('ID', 1),
('ID_', 3), ('ID__', 2), ('TXT', 'val_2')])
So, as you can see I have a perfect dictionary - number values are just numbers without quotes, string values are just strings with single quotes. I know, you will ask about the schema of the tables. So, here its is:
SQL> SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE
TABLE_NAME = 'TEST_TABLE';
COLUMN_NAME
------------------------------
DATA_TYPE
------------------------------
ID
NUMBER
SQL> SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS WHERE
TABLE_NAME = 'TEST_TABLE_2';
COLUMN_NAME
------------------------------
DATA_TYPE
------------------------------
ATTR
NUMBER
ID
NUMBER
TXT
VARCHAR2
SQL> SELECT COLUMN_NAME, DATA_TYPE FROM USER_TAB_COLUMNS
WHERE TABLE_NAME = 'TEST_TABLE_3';
COLUMN_NAME
------------------------------
DATA_TYPE
------------------------------
ID
NUMBER
So, it seems like one and the same query works good in the console, but does not work when using Python. Why is that?
EDIT
And here is a proof - a screen of two console windows. In the first console I run the query in sqlplus, in the second console I print sql query and the dictionary, which is used for binding variables:
EDIT
Oh, it's even more interesting. I was able to reproduce this error in Oracle shell and it looks like Oracle 11c bug. So, look at this:
Please, pay attention to the fact that ID field has a NUMBER type. And then pay attention to these two screens:
In the screen above you can see that everything is ok. However, if we slightly change it by adding OR T_0_1.ID=2 to the WHERE part, then it breaks:
So, this problem is reproducible even in Oracle shell. You can do it, using the schema I provided above.
EDIT
I updated the topic of my question, because it has nothing to do with Python. The whole problem with Oracle itself.
EDIT
BTW. My last comment does not contradict to the beginning part of my investigation. The thing is, if I have some data in TEST_TABLE_3, then the query breaks. And if I delete data, then is starts working. Here is a big proof:
How can data affect correctness of the query??
On your last screen just below the last line of the statement you have
CASE WHEN ( T_O.ID=1 AND ( T_0_0.ID=3 OR T_0_1.ID='VAL_1') )
there's an asterisk (now it helps, but sometimes it could lead in the wrong direction) showing the place of the encountered issue
T_0_1.ID='VAL_1'
in your table ID column is of Number type. 'VAL_1' - is Varchar.
As the comparison rules state:
When comparing a character value with a numeric value, Oracle converts the character data to a numeric value.
see (https://docs.oracle.com/database/121/SQLRF/sql_elements002.htm#SQLRF00214)
when oracle encounters this it tries to cast your string to number - and you get the error
How can data affect correctness of the query??
When there's no data in the table - there's no record returned from the table, hence there's no need the check the value of the column for equality - this comparison is not executed and no error shown

Expected CHAR got NUMBER

DB: Oracle 11g
Query:
SELECT CASE
WHEN rs.OPTION = '3'
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID
)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID
)
END AS PROPTS
FROM PR_OPTS
I am getting error 'expected CHAR got NUMBER', here EXTS,GROUP_ID & GRP_ID are numeric. Then how there is a chance of expecting CHAR?
Generally when Oracle compares different datatypes such as a NUMBER with a CHARACTER, implicit conversion kicks in and all is well (provided the data can be converted.) For example, if you have a function that expects a CHARACTER value but you pass it a NUMBER, all is well - Oracle simply converts the NUMBER to character.
E.g. a function like this:
create or replace function get_something(p_id VARCHAR2) return number ...
works if you call it with this:
get_dno(10);
or this:
get_dno('10');
and in SQL:
select * from some_table where numeric_column = '10' -- no problem.
A popular place where you see this kind of error is with the return values in CASE statements. For instance, you'll get that error if you have something like this:
SQL> SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
2 FROM dual
3 ;
SELECT CASE WHEN 1 = 1 THEN '1' ELSE 2 END
*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected CHAR got NUMBER
(The datatype from the first WHEN clause is what it expects in the other WHEN/ELSE clauses that follow.)
But in your case the WHEN and THEN both return counts - the datatypes are consistent. So, I think you have a red-herring in there.
As Alex mentioned above, OPTION is a keyword and if you try and create a table with that as a column name, Oracle disagrees:
SQL> create table dummy
2 (option varchar2(10)
3 );
(option varchar2(10)
*
ERROR at line 2:
ORA-00904: : invalid identifier
This works:
SQL> create table dummy
2 (option_col varchar2(10)
3 );
Table created.
or you could do it with quotes:
SQL> create table dummy
2 ("option" varchar2(10));
Table created.
But now you're in a world of hurt - you need quotes from now on:
SQL> select option from dummy;
select option from dummy
*
ERROR at line 1:
ORA-00936: missing expression
SQL> select d.option from dummy d;
select d.option from dummy d
*
ERROR at line 1:
ORA-01747: invalid user.table.column, table.column, or column specification
With quotes:
SQL> select d."option" from dummy d;
no rows selected
So, if your query is really giving you "expected CHAR, got NUMBER", it looks to me like something is off.
Essentially, it means some of the fields you are using aren't compatible with each other. It's basically a "type mismatch". Just check to see if any types of CHAR are being used with types of NUMBER. Then you can either switch the type of one, or simply use a conversion as part of the query.
The issue is OPTION = '3', the quotation marks indicate that you're looking for a string containing the solitary character 3.
Try this instead:
SELECT CASE
WHEN rs.OPTION = 3
THEN
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_GRP cg
ON cg.GROUP_ID = ex.GRP_ID)
ELSE
(SELECT COUNT(DISTINCT ex.EXTS) AS TMPCOL0
FROM CRSIDM.SUB_OPTS ex
INNER JOIN CRSIDM.SUB_OPTS_POL cg
ON cg.GROUP_ID = ex.GRP_ID)
END AS PROPTS
FROM PR_OPTS

Resources