Shorten the Table Names in Oracle - oracle

I have a requirement where i read table_name from user_tables and append 6 letters after the table_name at run time for e.g.
prev_table_name= F_ALIGN_PROF_PRD_MTH_SLS_NM2
New_table_name = prev_table_name_ABCDE
so new table name is exceeding the limit of 30 characters and i am getting an error.
to overcome this problem i am looking for a method so i can shorten the table_name at run time and append my 6 letters to it.
Kindly suggest any workaround fo this problem

How about something like this, then?
select substr(substr('F_ALIGN_PROF_PRD_MTH_SLS_NM2', 1, 24),
1,
instr(substr('F_ALIGN_PROF_PRD_MTH_SLS_NM2', 1, 24), '_', -1)) substr_table_name
from dual;
SUBSTR_TABLE_NAME
---------------------
F_ALIGN_PROF_PRD_MTH_

Do you want such result ?
select SUBSTR('prev_table_name_ABCDE' , 1, 6) from dual
Result : prev_t
If you want readable name you can take to last '_'
SELECT SUBSTR('prev_table_name_ABCDE', 1 ,INSTR('prev_table_name_ABCDE', '_',1,3)-1)
FROM dual;
Result :prev_table_name

I found one way to do it (its an temporary solution but it will work)
Read the table name and remove all vowels and numbers from it.

how about creating a a new table to store the old and new tablename?
my_table
oldname F_ALIGN_PROF_PRD_MTH_SLS_NM2
newname TEMP_ABCD

Related

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

Find next id from varchar in Oracle

I have a row that is a varchar(50) that has a unique constraint and i would like to get the next unique number for an new insert but with a given prefix.
My rows could look like this:
ID (varchar)
00010001
00010002
00010003
00080001
So if I would like to get the next unqiue number from the prefix "0001" it would be "00010004" but if I would want it for the prefix "0008" it would be "00080002".
There will be more then 1 millon entries in this table. Is there a way with Oracle 11 to perform this kind of operation that is fairly fast?
I know that this setup is totaly insane but this is what I have to work with. I cant create any new tables etc.
You can search for the max value of the specified prefix and increment it:
SQL> WITH DATA AS (
2 SELECT '00010001' id FROM DUAL UNION ALL
3 SELECT '00010002' id FROM DUAL UNION ALL
4 SELECT '00010003' id FROM DUAL UNION ALL
5 SELECT '00080001' id FROM DUAL
6 )
7 SELECT :prefix || to_char(MAX(to_number(substr(id, 5)))+1, 'fm0000') nextval
8 FROM DATA
9 WHERE ID LIKE :prefix || '%';
NEXTVAL
---------
00010004
I'm sure you're aware that this is an inefficient method to generate a primary key. Furthermore it won't play nicely in a multi-user environment and thus won't scale. Concurrent inserts will wait then fail since there is a UNIQUE constraint on the column.
If the prefix is always the same length, you can reduce the workload somewhat: you could create a specialized index that would find the max value in a minimum number of steps:
CREATE INDEX ix_fetch_max ON your_table (substr(id, 1, 4),
substr(id, 5) DESC);
Then the following query could use the index and will stop at the first row retrieved:
SELECT id
FROM (SELECT substr(id, 1, 4) || substr(id, 5) id
FROM your_table
WHERE substr(id, 1, 4) = :prefix
ORDER BY substr(id, 5) DESC)
WHERE rownum = 1
If you need to do simultaneous inserts with the same prefix, I suggest you use DBMS_LOCK to request a lock on the specified newID. If the call fails because someone is already inserting this value, try with newID+1. Although this involves more work than traditional sequence, at least your inserts won't wait on each others (potentially leading to deadlocks).
This is a very unsatisfactory situation for you. As other posters have pointed out - if you don't use sequences then you will almost certainly have concurrency issues. I mentioned in a comment the possibility that you live with big gaps. This is the simplest solution but you will run out of numbers after 9999 inserts.
Perhaps an alternative would be to create a separate sequence for each prefix. This would only really be practical if the number of prefixes is fairly low but it could be done.
ps - your requirement that > 1000000 records should be possible may, in fact, mean you have no choice but to redesign the database.
SELECT to_char(to_number(max(id)) + 1, '00000000')
FROM mytable
WHERE id LIKE '0001%'
SQLFiddle demo here http://sqlfiddle.com/#!4/4f543/5/0

How to resolve ORA 00936 Missing Expression Error?

Select /*+USE_HASH( a b ) */ to_char(date, 'MM/DD/YYYY HH24:MI:SS') as LABEL,
ltrim(rtrim(substr(oled, 9, 16))) as VALUE,
from rrfh a, rrf b,
where ltrim(rtrim(substr(oled, 1, 9))) = 'stata kish'
and a.xyz = b.xyz
The "from " (3rd line) part of the above query is giving me ORA-00936 Missing EXPRESSION error. Please Help me
NOTE :: rrfh table contains no data.
Remove the comma?
select /*+USE_HASH( a b ) */ to_char(date, 'MM/DD/YYYY HH24:MI:SS') as LABEL,
ltrim(rtrim(substr(oled, 9, 16))) as VALUE
from rrfh a, rrf b
where ltrim(rtrim(substr(oled, 1, 9))) = 'stata kish'
and a.xyz = b.xyz
Have a look at FROM
SELECTING from multiple tables You can include multiple tables in the
FROM clause by listing the tables with a comma in between each table
name
Remove the coma at the end of your SELECT statement (VALUE,), and also remove the one at the end of your FROM statement (rrf b,)
This answer is not the answer for the above mentioned question but it is related to same topic and might be useful for people searching for same error.
I faced the same error when I executed below mentioned query.
select OR.* from ORDER_REL_STAT OR
problem with above query was OR is keyword so it was expecting other values when I replaced with some other alias it worked fine.
update INC.PROV_CSP_DEMO_ADDR_TEMP pd
set pd.practice_name = (
select PRSQ_COMMENT FROM INC.CMC_PRSQ_SITE_QA PRSQ
WHERE PRSQ.PRSQ_MCTR_ITEM = 'PRNM'
AND PRSQ.PRAD_ID = pd.provider_id
AND PRSQ.PRAD_TYPE = pd.prov_addr_type
AND ROWNUM = 1
)
This happens every time you insert/ update and you don't use single quotes. When the variable is empty it will result in that error. Fix it by using ''
Assuming the first parameter is an empty variable here is a simple example:
Wrong
nvl( ,0)
Fix
nvl('' ,0)
Put your query into your database software and check it for that error. Generally this is an easy fix

PL/SQL query IN comma deliminated string

I am developing an application in Oracle APEX. I have a string with user id's that is comma deliminated which looks like this,
45,4932,20,19
This string is stored as
:P5_USER_ID_LIST
I want a query that will find all users that are within this list my query looks like this
SELECT * FROM users u WHERE u.user_id IN (:P5_USER_ID_LIST);
I keep getting an Oracle error: Invalid number. If I however hard code the string into the query it works. Like this:
SELECT * FROM users u WHERE u.user_id IN (45,4932,20,19);
Anyone know why this might be an issue?
A bind variable binds a value, in this case the string '45,4932,20,19'. You could use dynamic SQL and concatenation as suggested by Randy, but you would need to be very careful that the user is not able to modify this value, otherwise you have a SQL Injection issue.
A safer route would be to put the IDs into an Apex collection in a PL/SQL process:
declare
array apex_application_global.vc_arr2;
begin
array := apex_util.string_to_table (:P5_USER_ID_LIST, ',');
apex_collection.create_or_truncate_collection ('P5_ID_COLL');
apex_collection.add_members ('P5_ID_COLL', array);
end;
Then change your query to:
SELECT * FROM users u WHERE u.user_id IN
(SELECT c001 FROM apex_collections
WHERE collection_name = 'P5_ID_COLL')
An easier solution is to use instr:
SELECT * FROM users u
WHERE instr(',' || :P5_USER_ID_LIST ||',' ,',' || u.user_id|| ',', 1) !=0;
tricks:
',' || :P5_USER_ID_LIST ||','
to make your string ,45,4932,20,19,
',' || u.user_id|| ','
to have i.e. ,32, and avoid to select the 32 being in ,4932,
I have faced this situation several times and here is what i've used:
SELECT *
FROM users u
WHERE ','||to_char(:P5_USER_ID_LIST)||',' like '%,'||to_char(u.user_id)||',%'
ive used the like operator but you must be a little carefull of one aspect here: your item P5_USER_ID_LIST must be ",45,4932,20,19," so that like will compare with an exact number "',45,'".
When using it like this, the select will not mistake lets say : 5 with 15, 155, 55.
Try it out and let me know how it goes;)
Cheers ,
Alex
Create a native query rather than using "createQuery/createNamedQuery"
The reason this is an issue is that you cannot just bind an in list the way you want, and just about everyone makes this mistake at least once as they are learning Oracle (and probably SQL!).
When you bind the string '32,64,128', it effectively becomes a query like:
select ...
from t
where t.c1 in ('32,64,128')
To Oracle this is totally different to:
select ...
from t
where t.c1 in (32,64,128)
The first example has a single string value in the in list and the second has a 3 numbers in the in list. The reason you get an invalid number error is because Oracle attempts to cast the string '32,64,128' into a number, which it cannot do due to the commas in the string.
A variation of this "how do I bind an in list" question has come up on here quite a few times recently.
Generically, and without resorting to any PLSQL, worrying about SQL Injection or not binding the query correctly, you can use this trick:
with bound_inlist
as
(
select
substr(txt,
instr (txt, ',', 1, level ) + 1,
instr (txt, ',', 1, level+1) - instr (txt, ',', 1, level) -1 )
as token
from (select ','||:txt||',' txt from dual)
connect by level <= length(:txt)-length(replace(:txt,',',''))+1
)
select *
from bound_inlist a, users u
where a.token = u.id;
If possible the best idea may be to not store your user ids in csv! Put them in a table or failing that an array etc. You cannot bind a csv field as a number.
Please dont use: WHERE ','||to_char(:P5_USER_ID_LIST)||',' like '%,'||to_char(u.user_id)||',%' because you'll force a full table scan although with the users table you may not have that many so the impact will be low but against other tables in an enterprise environment this is a problem.
EDIT: I have put together a script to demonstrate the differences between the regex method and the wildcard like method. Not only is regex faster but it's also a lot more robust.
-- Create table
create table CSV_TEST
(
NUM NUMBER not null,
STR VARCHAR2(20)
);
create sequence csv_test_seq;
begin
for j in 1..10 loop
for i in 1..500000 loop
insert into csv_test( num, str ) values ( csv_test_seq.nextval, to_char( csv_test_seq.nextval ));
end loop;
commit;
end loop;
end;
/
-- Create/Recreate primary, unique and foreign key constraints
alter table CSV_TEST
add constraint CSV_TEST_PK primary key (NUM)
using index ;
alter table CSV_TEST
add constraint CSV_TEST_FK unique (STR)
using index;
select sysdate from dual;
select *
from csv_test t
where t.num in ( Select Regexp_Substr('100001, 100002, 100003 , 100004, 100005','[^,]+', 1, Level) From Dual
Connect By Regexp_Substr('100001, 100002,100003, 100004, 100005', '[^,]+', 1, Level) Is Not Null);
select sysdate from dual;
select *
from csv_test t
where ('%,' || '100001,100002, 100003, 100004 ,100005' || ',%') like '%,' || num || ',%';
select sysdate from dual;
select *
from csv_test t
where t.num in ( Select Regexp_Substr('100001, 100002, 100003 , 100004, 100005','[^,]+', 1, Level) From Dual
Connect By Regexp_Substr('100001, 100002,100003, 100004, 100005', '[^,]+', 1, Level) Is Not Null);
select sysdate from dual;
select *
from csv_test t
where ('%,' || '100001,100002, 100003, 100004 ,100005' || ',%') like '%,' || num || ',%';
select sysdate from dual;
drop table csv_test;
drop sequence csv_test_seq;
Solution from Tony Andrews works for me. The process should be added to "Page processing" >> "After submit">> "Processes".
As you are Storing User Ids as String so You can Easily match String Using Like as Below
SELECT * FROM users u WHERE u.user_id LIKE '%'||(:P5_USER_ID_LIST)||'%'
For Example
:P5_USER_ID_LIST = 45,4932,20,19
Your Query Surely Will return Any of 1 User Id which Matches to Users table
This Will Surely Resolve Your Issue , Enjoy
you will need to run this as dynamic SQL.
create the entire string, then run it dynamically.

Oracle statement

Tables records as below
D:\HOME\DOC\FILE\2001\12\TT-12S2Q99-EE-EE1.pdf
D:\HOME\DOC\FILE\2002\02\TT-12S2Q94-EE-EE1.xml
D:\HOME\DOC\FILE\2005\05\TT-12S2Q98-EE-EE1.pdf
D:\HOME\DOCS\TEMPFILE\TT-12S2Q88-EE-EE1.pdf
I want to extract those file names only. The result should be
TT-12S2Q99-EE-EE1
TT-12S2Q94-EE-EE1
TT-12S2Q98-EE-EE1
TT-12S2Q88-EE-EE1
Anyone can give me a hand ?
You can use INSTR with the third parameter negative to search backwards in the string from the end (something I didn't know you could do until a few minutes ago). Combine that with a SUBSTR and you should have what you want:
SQL> select filename from mytable;
FILENAME
--------------------------------------------------------------------------------
C:\path\to\some\file.txt
SQL> select substr(filename, instr(filename, '\', -1) + 1) from mytable;
SUBSTR(FILENAME,INSTR(FILENAME,'\',-1)+1)
--------------------------------------------------------------------------------
file.txt
Take a look at the SUBSTR and INSTR functions.
If you're still stuck after that, post your best attempt at what you've done.

Resources