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
Related
I am new to Oracle SQL Developer, and today while running this
select r.id, r.date, it.group, it.comment, it.item, it.remark, r.summary,
substr (it.remark, instr(it.remark,'ABC')+8,7 ) as label1,
cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer) as label2
from it_table it
inner join sp_table sp on sp.id = substr (it.remark, instr(it.remark,'ABC')+8,7 ) and sp.label_id = cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer)
inner join sq_table sq on sq.id = sp.id
where it.date > '01-jan-2020' and it.remark like '%ABC%' and it.group= 'O'
order by sp.id, it.id;
it caught the error:
ORA-01722: invalid number
01722. 00000 - "invalid number"
*Cause: The specified number was invalid.
*Action: Specify a valid number.
I think the problem lies with the extraction as in row 3 (cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer)), where I need to convert a string into a number using cast.
According to doc, the error occurs when an attempt is made to convert a character string into a number, and the string cannot be converted into a valid number.
So, I tried replacing:
cast(substr (it.remark, instr(it.remark,'-')+1,3 ) as integer)
with
to_number(substr (it.remark, instr(it.remark,'-')+1,3 ))
and even tried to_char but didn't work. However, the original script seems to work fine in sandbox database. I am wondering why this is happening. Any help is greatly appreciated.
Update:
Sample data it:
ID DATE NAME GROUP REMARK COMMENT ...
100 20-10-08 AABC X ACS LOCATION 1 - ABC IDD x105213-1
101 20-10-08 AxB Y MN LOCATION 8 - ABC IDD x105244-2
...
Sample data sp:
ID DATE NAME GROUP label_id
105213 20-10-08 AABC X 1
105244 20-10-08 AxB Y 2
...
It turns out that the error was caused by having 2 - in remark which lead to ambiguity and I just need the second one.
New question then:
How do I extract the last - in the value to join with another value in the other column?
Use cast with default null on conversion error to avoid exception and investigate the cause of the failed conversion.
Example
with dt as
(select '001' remark from dual union all
select ' 2' from dual union all
select 'OMG' from dual)
select substr(remark,1,3) txt,
cast (substr(remark,1,3) as INT default null on conversion error) num
from dt;
TXT NUM
--- ----------
001 1
2 2
OMG
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.
I have defined the following procedure in PL/SQL:
CREATE OR REPLACE PROCEDURE deleteFromStudyCase(studycase_id IN NUMBER)
IS
VAL_CARRIER_ID_GLOBAL NUMBER(19,0);
EST_OBJ_ID_GLOBAL NUMBER(19,0);
INVEST_TASK_ID_GLOBAL NUMBER(19,0);
BEGIN
-- Fill the variables
SELECT IT.ID into INVEST_TASK_ID_GLOBAL
FROM T_INVESTIGATIONTASK IT
WHERE IT.STUDYCASE_ID = studycase_id;
SELECT EO.ID into EST_OBJ_ID_GLOBAL
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = INVEST_TASK_ID_GLOBAL;
SELECT VC.ID into VAL_CARRIER_ID_GLOBAL
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = EST_OBJ_ID_GLOBAL;
....many DELETE statements...
END deleteFromStudyCase;
When I try to use it like this:
BEGIN
DELETEFROMSTUDYCASE(30111);
END;
At runtime it fails with this error:
Error report -
ORA-01422: exact fetch returns more than requested number of rows
ORA-06512: at "DELETEFROMSTUDYCASE", line 9
ORA-06512: at line 2
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
Meaning that one of the selects is returning more than just one value as expected. I tried so to run the select statements separately to see which one was the problem but:
SELECT IT.ID
FROM T_INVESTIGATIONTASK IT
WHERE IT.STUDYCASE_ID = 30111;
is returning only 10053.
SELECT EO.ID
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = 10053;
is returning only 933.
SELECT VC.ID
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = 933;
is returning only 12.
Since this part of my database has a tree structure I have also created the following procedure:
CREATE OR REPLACE PROCEDURE deleteFromInvestigationTask(invest_task_id IN NUMBER)
IS
VAL_CARRIER_ID_GLOBAL NUMBER(19,0);
EST_OBJ_ID_GLOBAL NUMBER(19,0);
BEGIN
-- Fill the variables
SELECT EO.ID into EST_OBJ_ID_GLOBAL
FROM T_ESTIMATIONOBJECT EO
WHERE EO.INVESTIGATIONTASK_ID = invest_task_id;
SELECT VC.ID into VAL_CARRIER_ID_GLOBAL
FROM T_VALIDATIONCARRIER VC
WHERE VC.IA_ESTIMATIONOBJECT_ID = EST_OBJ_ID_GLOBAL;
...many DELETE statements...
And this one works correctly.
So the other one should work, why do I continue to get that error? What else could it be?
I found the problem.
In the first procedure, the parameter name is studycase_id which is also the name of a column in the table T_INVESTIGATIONTASK so the WHERE condition IT.STUDYCASE_ID = studycase_id is wrong: that's why the first SELECT is failing. I changed the parameter name in study_case_id and solved my problem.
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
i'm currently writing a school assignment but got stuck. Unfortunately I have no reference material to browse through and oracle's user manuals are anything but friendly.
The assignment is as followed: "Create a trigger on table sms_budget_abonnement with help of a stored procedure which shows the bill in a new table when a user has passed the max_number of texts to be send within his/hers subscription
these are the relevant tables (<>English translation):
KLANTGEGEVENS <customer information>
NAAM <name> GESLACHT ADRES WOONPLAATS MOBIEL_NUMMER REKENINGNUMMER <billing_number> ABONNEMENTSVORM <subscription type> START_DATUM EIND_DATUM
SMS-BERICHT <text_message>
MOBIELE_NUMMER_VERZENDER <mobile_number_sender> MOBIELE_NUMMER_ONTVANGER LENGTE DATUM TIJD INHOUD (GEDOCEERD)
ABONNEMENTSVORMEN <subscription_type>
NAAM <subscription_name> BASISKOSTEN SMS <max_number_of_text_messages> SMS-BOETE <price per extra message> BELLEN
FACTUUR <billing sheet>
REKENINGNUMMER <billing_number> DATE BEDRAG <price> STATUS
This is the code/query I have written:
CREATE OR REPLACE TRIGGER opdracht_2e
BEFORE INSERT ON SMSBERICHT
FOR EACH ROW
DECLARE
NR_OF_PERSON NUMBER;
NR_OF_TEXT_MESSAGES NUMBER;
MAX_NUMBER_SMS NUMBER;
REKENING_NUMMER VARCHAR(255);
BOETE NUMBER;
BEGIN
select DISTINCT MOBIELNUMMERVERZENDER INTO NR_OF_PERSON
FROM SMSBERICHT;
SELECT COUNT(*) INTO NR_OF_TEXT_MESSAGES
FROM SMSBERICHT
WHERE MOBIELNUMMERVERZENDER = NR_OF_PERSON;
SELECT SMS into MAX_NUMBER_SMS
FROM ABONNEMENTSVORMEN av
JOIN Klantgegevens k ON k.ABBONEMENTSVORM = av.naam
WHERE k.mobielnummmer = NR_OF_PERSON;
SELECT REKENINGNUMMER into REKENING_NUMMER
FROM Klantgegevens
WHERE mobielnummer = NR_OF_PERSON;
SELECT SMS_BOETE INTO BOETE
FROM ABBONEMENTSVORMEN av
JOIN Klantgegevens k on k.ABBONEMENTSVORM = av.naam
WHERE k.mobielnummer = NR_OF_PERSON;
IF(NR_OF_TEXT_MESSAGES > MAX_NUMBER_SMS) THEN
insert into factuur
values (REKENING_NUMMER, SYSDATE, (NR_OF_TEXT_MESSAGES - MAX_NUMBER_SMS) * BOETE, "TE BETALEN");
END IF;
END;
However I'm getting the following errors which don't really help me in the right direction, if anyone care's to clarify these messages to me that would be awesome.
Project: sqldev.temp:/IdeConnections%23hanze.jpr
hanze
Error(16,1): PL/SQL: SQL Statement ignored
Error(19,7): PL/SQL: ORA-00904: "K"."MOBIELNUMMMER": invalid identifier
Error(25,1): PL/SQL: SQL Statement ignored
Error(26,6): PL/SQL: ORA-00942: table or view does not exist
Error(31,1): PL/SQL: SQL Statement ignored
Error(32,84): PL/SQL: ORA-00984: column not allowed here
Thanks in advance!
You have an extra m in line 19:
WHERE k.mobielnummmer = NR_OF_PERSON;
The second error is in this section, specifically the FROM lone:
SELECT SMS_BOETE INTO BOETE
FROM ABBONEMENTSVORMEN av
JOIN Klantgegevens k on k.ABBONEMENTSVORM = av.naam
WHERE k.mobielnummer = NR_OF_PERSON;
An earlier reference only has one B; ABBONEMENTSVORMEN. So you are using the wrong name. It doesn't help that the table descriptions you showed are not accurate. It would have better to show the actual definitions, e.g. from describe <table>.
You have a string value enclosed in double quotes instead of single quotes inthis line:
values (REKENING_NUMMER, SYSDATE, (NR_OF_TEXT_MESSAGES - MAX_NUMBER_SMS) * BOETE, "TE BETALEN");
It should be 'TE BETALEN'. Double-quoted or unquoted strings are interpreted as identifiers, in this context a column name.
All pretty simple mistakes that were fairly clearly indicated by the error messages.