I want column names with symbols
i.e. {ImportId:week}
I tried placing a " on either side of each symbol and string
i.e. "{""ImportId"":""week""}" like this`
CREATE TABLE EXAMPLE
(
"{""ImportId"":""week""}" VARCHAR2(100)
)
but I get the error:
ORA-03001: unimplemented feature
A pair of double-quotes bounds an identifier. A column can have only one identifier. So just strip out all the unnecessary double-quotes and make the whole piece a single identifier:
CREATE TABLE EXAMPLE
(
"{ImportId:week}" VARCHAR(100)
)
Incidentally, are you really sure you want to do this. Using unapproved symbols in column names is really not necessary and it's not idiomatic. The long term consequence of this naming convention will most likely be a continual low-grade annoyance experienced by everybody who has to work with this table.
Related
Creating a mySomeTable table with 2 fields
create table mySomeTable (
IDRQ VARCHAR2(32 CHAR),
PROCID VARCHAR2(64 CHAR)
);
Creating an index on the table by the PROCID field
create index idx_PROCID on mySomeTable(trunc(PROCID));
Inserting records:
insert into mySomeTable values ('a', '1'); -- OK
insert into mySomeTable values ('b', 'c'); -- FAIL
As you can see, an error has been made in the index construction script and the script will try to build an index on the field using the trunc() function.
trunct() is a function for working with dates or numbers, and the field has the string type
This index building script successfully works out and creates an index without displaying any warnings and errors.
An index is created on the table using the TRUNC(TO_NUMBER(PROCID)) function
When trying to insert or change an entry in the table, if PROCID cannot be converted to a number, I get the error ORA-01722: invalid number, which is actually logical.
However, the understanding that I am working in a table with rows and adding string values to the table, and the error is about converting to a number, was misleading and not understanding what is happening...
Question: Why does Oracle change the index construction function, instead of giving an error? And how can this be avoided in the future?
Oracle version 19.14
Naturally, there was only one solution - to create the right index with the right script
create index idx_PROCID on mySomeTable(PROCID);
however, this does not explain, to me, this Oracle behavior.
Oracle doesn't know if the index declaration is wrong or the column data type is wrong. Arguably (though some may well disagree!) Oracle shouldn't try to second-guess your intentions or enforce restrictions beyond those documented in the manual - that's what user-defined constraints are for. And, arguably, this index acts as a form of pseudo-constraint. That's a decision for the developer, not Oracle.
It's legal, if usually ill-advised, to store a number in a string column. If you actually intentionally chose to store numbers as strings - against best practice and possibly just to irritate future maintainers of your code - then the index behaviour is reasonable.
A counter-question is to ask where it should draw the line - if you expect it to error on your index expression, what about something like
create index idx_PROCID on mySomeTable(
case when regexp_like(PROCID, '^\d.?\d*$') then trunc(PROCID) end
);
or
create index idx_PROCID on mySomeTable(
trunc(to_number(PROCID default null on conversion error))
);
You might actually have chosen to store both numeric and non-numeric data in the same string column (again, I'm not advocating that) and an index like that might then useful - and you wouldn't want Oracle to prevent you from creating it.
Something that obviously doesn't make sense and shouldn't be allowed to you is much harder for software to evaluate.
Interestingly the documentation says:
Oracle recommends that you specify explicit conversions, rather than rely on implicit or automatic conversions, for these reasons:
...
If implicit data type conversion occurs in an index expression, then Oracle Database might not use the index because it is defined for the pre-conversion data type. This can have a negative impact on performance.
which is presumably why it actually chooses here to apply explicit conversion when it creates the index expression (which you can see in user_ind_expressions - fiddle)
But you'd get the same error if the index expression wasn't modified - there would still be an implicit conversion of 'c' to a number, and that would still throw ORA-01722. As would some strings that look like numbers if your NLS settings are incompatible.
I am trying to create an Oracle Spatial index but seeing strange behavior.
I have a table in my schema as follows:
CREATE TABLE "Event" (
"EventID" NUMBER(32,0) GENERATED ALWAYS AS IDENTITY INCREMENT BY 1 START WITH 1 NOT NULL,
"Name" NVARCHAR2(30),
"Location" "SDO_GEOMETRY" NOT NULL,
CONSTRAINT "PK_EVENT" PRIMARY KEY ("EventID")
) ;
This works fine and I know I have to create an entry in user_sdo_geom_metadata, that works as you would expect with the following:
insert into user_sdo_geom_metadata (table_name,column_name,diminfo,srid) values ('Event','Location',
sdo_dim_array(sdo_dim_element('X',-180.0,180.0, 0.005),sdo_dim_element('Y',-90.0,90.0, 0.005)), 4326);
This reports success and when I do a select on user_sdo_geom_metadata I see the row. However, when I try to create the spatial index with:
CREATE INDEX "EVINDEX" ON "Event" ("Location") INDEXTYPE IS MDSYS.SPATIAL_INDEX_V2
I get the following error:
SQL Error [29855] [99999]: ORA-29855: error occurred in the execution of ODCIINDEXCREATE routine
ORA-13203: failed to read USER_SDO_GEOM_METADATA view
ORA-13203: failed to read USER_SDO_GEOM_METADATA view
ORA-06512: at "MDSYS.SDO_INDEX_METHOD_10I", line 10
The weird thing is the Index looks like it's been created.
select * from all_indexes where table_name='Event';
Shows the index??? The other odd thing is when I do a select * on ALL_SDO_GEOM_METADATA, no rows are returned??? I'm connecting as a user with almost every privilege and role but not as SYSDBA. I can't get my head around this one.
UPDATE
Incredibly, this seems to be a case sensitivity issue. If you change the table and column names to all UPPERCASE it works. It seems my neverending disappointment in Oracle has a whole new chapter. Going to try to struggle through this somehow, but like most things with Oracle, it's one unrelenting slog to get anything done :(
The documentation says:
The table name cannot contain spaces or mixed-case letters in a quoted string when inserted into the USER_SDO_GEOM_METADATA view, and it cannot be in a quoted string when used in a query (unless it is in all uppercase characters).
and
The column name cannot contain spaces or mixed-case letters in a quoted string when inserted into the USER_SDO_GEOM_METADATA view, and it cannot be in a quoted string when used in a query (unless it is in all uppercase characters).
However, it also says:
All letters in the names are converted to uppercase before the names are stored in geometry metadata views or before the tables are accessed. This conversion also applies to any schema name specified with the table name.
which you can see if you query the user_sdo_geom_metadata view after your insert; the mixed-case names have become uppercase EVENT and LOCATION.
But then:
Note: Letter case conversion does not apply if you use mixed case (“CamelCase”) names enclosed in quotation marks. However, be aware that many experts recommend against using mixed-case names.
And indeed, rather unintuitively, it seems to work if you include the quotes in the user_sdo_geom_metadata insert:
insert into user_sdo_geom_metadata (table_name,column_name,diminfo,srid)
values (
'"Event"',
'"Location"',
sdo_dim_array(sdo_dim_element('X',-180.0,180.0, 0.005),
sdo_dim_element('Y',-90.0,90.0, 0.005)), 4326
);
db<>fiddle
So it appears that the values from the view are at some point concatenated into a dynamic SQL statement, which would explain some of the behaviour.
I am trying to code a sqlldr.ctl file WHEN Clause to limit the records imported to those matching a portion of the current Schema's name.
The code I have (which does NOT work) is:
LOAD DATA
TRUNCATE INTO TABLE TMP_PRIM_ACCTS
when REGION_NUM = substr(user,-3,3)
Fields terminated by "|" Optionally enclosed by '"'
Trailing NULLCOLS
( PORTFOLIO_ACCT,
PRIMARY_ACCT_ID NULLIF (PRIMARY_ASSET_ID="NULL"),
REGION_NUM NULLIF (PARTITION_NUM="NULL")
)
sqlldr returns:
SQL*Loader-350: Syntax error at line 3.
Expecting quoted string or hex identifier, found "substr".
when PARTITION_NUM = substr(user,-3,3)
I cannot put single quotes around "user", because that turns it into the literal string "user". Can anyone explain how I can reference the "active" User in this WHEN Clause?
Thank you!
Can you try something like this? (now I can't make test with SQLLDR, but this is syntax I used for changing values):
when REGION_NUM = "substr(:user,-3,3)"
It doesn't look like you can. The documentation only shows fixed values:
Trying to use an expression in when that clause (or in nullif; thought I'd try to see if you could cause a rejection based on null PK value) you just see the literal value in the log:
Table TMP_PRIM_ACCTS, loaded when REGION_NUM = 0X73756273747228757365722c2d332c3329(character 'substr(user,-3,3)')
which is sort of what you referred when you said you couldn't quote user, but you'd have to quite the whole thing anyway. Using :user doesn't work either, the colon is seen as just another character, it doesn't try to find a column called user instead.
The simplest approach may be to pre-process the data file and remove any rows which don't match the pattern (e.g. via a regex). That would actually be slightly easier if you used an external table instead of SQL*Loader.
Alternatively, generate your control file and embed the correct literal value based on the user you'll connect as.
How can I list all stored procedures/arguments of a package with their original name.
When I do the following all names are in uppercase:
SELECT object_name, argument_name, in_out, data_type FROM All_arguments;
Is there a way the find the original name (original case).
Say when I create a stored procedure with the name "getMyStoredProcedure", I would like the get the name in that case.
By default, Oracle identifiers are case-insensitive. Identifiers are automatically converted to upper case in the data dictionary.
You can prevent that upper casing by choosing to use case-sensitive identifiers which requires that you enclose the identifiers in double-quotes. If you
CREATE PROCEDURE "myCamelCaseProc"
...
the procedure name will remain myCamelCaseProc in the data dictionary. If you do that, however, you would need to enclose the identifier in double-quotes every time you reference it and you would have to get the casing correct every time. That is generally a poor architectural choice to make-- future developers will likely curse your name when they find themselves trying to read code that is littered with double-quotes and where identifiers are unexpectedly case-sensitive.
I'm currently porting a Code Igniter based application from MySQL to Oracle (11g) for a specific client. Both the MySQL and Oracle back-ends have to work in conjunction (i.e. we cannot drop the one or the other).
The MySQL DB uses around 100 tables of which ALL identifiers are in lowercase. When I migrate this DB to Oracle, using Oracle's SQL Developer tool, I end up with a 'properly' converted DB, but... with all uppercase identifiers.
Now, for normal usage this isn't really a problem, but the issue arises when using the CI Active Record class. It generates queries to the effect of:
SELECT "somecolumn" FROM "sometable" WHERE "someothercolumn" = somevalue
The issue is that when the " quotes are used for these identifiers, Oracle forces these identifiers to be interpreted in a case sensitive way, which in this case is wreaking havoc.
Patching the core code of CI and/or the application to either make all queries use case insensitive identifiers (i.e. by dropping the usage of the " quotes around the identifiers) or to convert all identifiers to uppercase ones on the fly, is IMO not desired, as a potential future framework upgrade is then compromised. Renaming ALL MySQL identifiers to become in uppercase is also a very unattractive scenario and has an even bigger impact on the application itself -- not an option for sure.
Instead, what I would like to achieve, is to have the migration process (i.e. using SQL Developer) simply respecting the case of the source DB and to perform the conversion exactly as it does up to now, with the exception that the identifiers do not get changed to their uppercase version.
I have searched a fair deal online to find a way to achieve this, and so far it has been to no avail.
Does anyone know if this can be done, and if so: how?
Is the conversion to all uppercase identifiers by any chance a global DB setting, perhaps?
I would have assumed this to be a trivial thing, but I haven't been able to figure it out so far and what little related references that I did come across do not sound very promising...
If you can acquire a schema script created by the database migration all you need to do is change the identifiers ( tablenames, view names, column names etc ) to be surrounded with double quotation marks. (I'm not sure if SQL Developer migrations actually has the option to preserve the case).
Without the quote marks Oracle will assume all identifiers are case-insensitive. However this is stored internally as upper case strings in the data dictionary. By using quote marks will force Oracle to use the exact case for the schema objects.
eg.
create table Customers
(
Name varchar2(100),
CreationDate date not null
);
will create CUSTOMERS internally in the data-dictionar and you can write queries like:
select name, creationdate from customers;
alternatively:
create table "Customers"
(
"Name" varchar2(100),
"CreationDate" date not null
);
will create "Customers" internally. You can only write queries using quotes and exact case:
select "Name", "CreationDate" from "Customers";
I have hit this before and simply edited oci8_driver.php (../system/database/oci) as follows:
// The character used for excaping
var $_escape_char = '"';
to
// The character used for excaping
var $_escape_char = '';
Stewart