Split owner and object name in Oracle - oracle

Given an object identified by the form owner.tablename; how do I split the owner and table name up?
Both my ideas of either string tokenization or select owner, object_name from all_objects where owner || '.' || object_name = 'SCHEMA.TABLENAME' seem like hacks.

You can use DBMS_UTILITY.name_tokenize for this purpose.
This procedure calls the parser to parse the given name as "a [. b [.
c ]][# dblink ]". It strips double quotes, or converts to uppercase if
there are no quotes. It ignores comments of all sorts, and does no
semantic analysis. Missing values are left as NULL.
e.g.
DBMS_UTILITY.NAME_TOKENIZE
( name => 'SCHEMA.TABLENAME'
, a => v_schema
, b => v_object_name
, c => v_subobject -- ignore
, dblink => v_dblink
, nextpos => v_nextpos -- ignore
);
http://docs.oracle.com/cd/E11882_01/appdev.112/e40758/d_util.htm#BJEFIFBJ

SELECT SUBSTR('SCHEMA.TABLENAME', 0, INSTR('SCHEMA.TABLENAME', '.') - 1) OWNER,
SUBSTR('SCHEMA.TABLENAME', INSTR('SCHEMA.TABLENAME', '.') + 1) TABLE_NAME
FROM DUAL

Related

How to use REGEXP_SUBSTR to filter?

I have a select query which is working in postgres , but not in Oracle
The Select Query Uses regexp_split_to_array , which is not suppourted in Oracle
The regexp_split_to_array used here is to filter non working days
select
*
from
department
where
dept_status = 'A'
AND NOT (
#{DAY} = any ( regexp_split_to_array(lower(non_working_days), ',')))
AND dept_loc = 'US'
http://sqlfiddle.com/#!4/fbac4/4
Oracle does not have a function regexp_split_to_array . Instead you can use LIKE (which is much faster than regular expressions) to check for a sub-string match (including the surrounding delimiters so you match a complete term):
SELECT *
FROM department
WHERE dept_status = 'A'
AND ',' || lower(non_working_days) || ',' NOT LIKE '%,' || :DAY || ',%'
AND dept_loc = 'US'
Note: You should pass in variables using bind variables such as :day or ? (for an anonymous bind variable) rather than relying on a pre-processor to replace strings as it will help to prevent SQL injection attacks.
fiddle

How to run Postgres psql "slash" commands using Sequel

Using Sequel, is it possible to run PostgreSQL "slash" commands, such as \d, \dn or \copy table...?
I tried using
DB.run(‘\dn’)
but I got a syntax error, because, presumably Sequel is trying to parse the SQL, or Postgres can’t understand the SQL, because these are commands that are handled by the psql application.
The slash commands are features of psql, not the server so they're only accessible in psql. However, some of them (such as \copy) have equivalents that the server does understand and the rest are shortcuts to queries of the system tables. If you run psql -E:
-E
--echo-hidden
Echo the actual queries generated by \d and other backslash commands. You can use this to study psql's internal operations. This is equivalent to setting the variable ECHO_HIDDEN to on.
then you can see the queries and you should be able to use those queries with DB.run or DB.fetch(...).all. For example:
$ psql -E -d...
=# \d
********* QUERY **********
SELECT n.nspname as "Schema",
c.relname as "Name",
CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'table' WHEN 'I' THEN 'index' END as "Type",
pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','p','v','m','S','f','')
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND n.nspname !~ '^pg_toast'
AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
**************************
=# \dt
********* QUERY **********
SELECT n.nspname as "Schema",
c.relname as "Name",
CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'm' THEN 'materialized view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' WHEN 'f' THEN 'foreign table' WHEN 'p' THEN 'table' WHEN 'I' THEN 'index' END as "Type",
pg_catalog.pg_get_userbyid(c.relowner) as "Owner"
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','p','')
AND n.nspname <> 'pg_catalog'
AND n.nspname <> 'information_schema'
AND n.nspname !~ '^pg_toast'
AND pg_catalog.pg_table_is_visible(c.oid)
ORDER BY 1,2;
**************************

Issue while running a query within a procedure

I have a procedure that expects a SELECT statement as a parameter.
If I run the SELECT Statement out of the procedure, it runs fine, but when I run it within the procedure i get the error:
The procedure :
data_dump(query_in => 'select * from reservation where type not in ('H','PURGE','E') ',
file_in => 'export_'||months_from||''||months_to||'.csv',
directory_in => 'C:\Users\Administrator\Desktop\test',
delimiter_in => '|' );
The query itself gives me the expected result.
select * from reservation where type not in ('H','PURGE','E', '|| other ||')
The error is: encountered the symbol 'H'.
Can it be because of the single quotes around the IN condition?
getting error missing right parenthesis:
(trunc(a.update_date) between (select add_months(TRUNC(SYSDATE), -(]'|| months_from ||q'[') ) from dual) and (select add_months(TRUNC(SYSDATE), -(]'|| months_to ||q'[') from dual))]'
You're passing quoted arguments within a string. You need to either escape those internal quotes:
data_dump(query_in => 'select * from reservation where type not in (''H'',''PURGE'',''E'') ',
file_in => 'export_'||months_from||''||months_to||'.csv',
directory_in => 'C:\Users\Administrator\Desktop\test',
delimiter_in => '|' );
Or use the alternative quoting mechanism:
data_dump(query_in => q'[select * from reservation where type not in ('H','PURGE','E') ]',
...
With your 'other' value you need to still include that in its own escape quotes:
data_dump(query_in => 'select * from reservation where type not in (''H'',''PURGE'',''E'','''|| other ||''')',
...
or (getting less readable now, perhaps):
data_dump(query_in => q'[select * from reservation where type not in ('H','PURGE','E',']' || other || q'[')]',
...
You can use dbms_output to debug this sort of thing, printing the generated argument and seeing if that matches what you've been running manually.
With your third partial code you've put closing single quotes after the (presumably numeric) variables:
(trunc(a.update_date) between (select add_months(TRUNC(SYSDATE), -(]'|| months_from ||q'[') ) from dual) and (select add_months(TRUNC(SYSDATE), -(]'|| months_to ||q'[') from dual))]'
^ ^
and you are, as the message says, missing a closing parenthesis in the second add_month call; so it should be (where ... is the rest of the statement that you haven't shown):
q'[ ... (trunc(a.update_date) between (select add_months(TRUNC(SYSDATE), -(]'
|| months_from ||q'[) ) from dual) and (select add_months(TRUNC(SYSDATE), -(]'
|| months_to ||q'[) ) from dual))]'
Again, this is basic debugging you can do by printing the generated statement and inspecting it or trying to run it manually.
Also you don't need the inner select from dual stuff or all the parentheses; you can just do:
q'[ ... trunc(a.update_date) between add_months(TRUNC(SYSDATE), -]'
|| months_from ||q'[) and add_months(TRUNC(SYSDATE), -]'|| months_to ||q'[)]'

how to get the '' for each string in a listagg?

I have the following query :
SELECT
ix.dt AS DT,
ix.UDBENCH_UDIDX AS UDFO,
' .' || REPLACE(REPLACE( ix.UDBENCH_UDIDX,' ',''),'IS','') AS PF_TICKER,
i.szbez AS PORTFOLIO_NAME,
ix.rm_generic_inst_type_l1,
ix.rm_generic_inst_type_l2,
ix.scd_sec_type,
m.ud_isin AS SECURITY_ID,
'%' AS POS_TYPE,
ix.sec_weight AS QUANTITY,
ix.sec_ccy,
ix.sec_price AS MKT_PRICE,
'' AS COST_PX,
'' AS POSITION_VALUE_AC,
'' AS POSITION_VALUE_FC,
m.ud_sedol AS UD_SEDOL,
m.ud_bbgid AS UD_ID_BB_UNIQUE,
m.ud_cusip AS UD_CUSIP,
m.ud_bbgid AS UD_BBGID,
m.inst_name AS INST_NAME,
ix.idas AS IDAS,
m.ud_scd_securityid AS UD_SCD_SECURITYID
FROM XXXX ix
INNER JOIN XXXXR i ON (i.udidx = ix.UDBENCH_UDIDX),
XXXXX m
WHERE ix.dt >= to_date(sdt_start,'DD.MM.YYYY')
AND ix.dt <= to_date(sdt_end,'DD.MM.YYYY')
AND ix.UDBENCH_UDIDX IN (select listagg( udfo,',') within group(ORDER BY udfo)
from XXXXX where pf_ticker is null )
AND i.szbez LIKE '%DFLT%'
AND ix.idas = m.idas;
I would like the part :
AND ix.UDBENCH_UDIDX IN (select listagg( udfo,',') within group(ORDER
BY udfo)
from XXXXX where pf_ticker is null )
Equivalent to : ix.UDBENCH_UDIDX IN ('blal','bll',blc') but it shows ix.UDBENCH_UDIDX IN (blal,bll,blc) and the result of my query is an empty table, do you know how to set listagg to have this result ( 'blal','bll',blc' instead of blal,bll,blc)?
Thanks
The IN operator doesn't work like that. You'd be comparing the UDBENCH_UDIDX values with a single string containing all udfo values, not all of the individual values of that column.
You can just use a subquery without the listagg():
AND ix.UDBENCH_UDIDX IN (select udfo from XXXXX where pf_ticker is null)
Or you can join to that table instead of using a subquery at all; something like:
FROM XXXX ix
INNER JOIN XXXXR i ON (i.udidx = ix.UDBENCH_UDIDX)
INNER JOIN XXXXX m ON (m.udfo = ix.UDBENCH_UDIDX)
WHERE ix.dt >= to_date(sdt_start,'DD.MM.YYYY')
AND ix.dt <= to_date(sdt_end,'DD.MM.YYYY')
AND i.szbez LIKE '%DFLT%'
AND ix.idas = m.idas
AND m.pf_ticker is null;
... assuming the old-style join to XXXXX m is supposed to be getting the data related to the subquery you're doing - it's hard to tell with obfuscated names. (It's not a good idea to mix old and new style joins anyway; or to use old-style joins at all). It's possible you might want that to be an outer join, or the driving table, or something else - again can't infer that from the information provided.
If you already had a set of string literals to look for then you would do something like:
IN ('val1', 'val2', 'val3')
but you don't have string literals, you have string values from a table, which are not the same. You don't need to, and shouldn't, enclose those column values in single quotes within the query. The single quotes denote a literal value which is to be treated as a string; the values in the column are already strings.
You can actually do what you asked:
select '''' || listagg(udfo, ''',''') within group (order by udfo) || '''' from ...
which would give you a comma-separated list of quoted values from your table (or an empty string, which is the same as null, if there are no matching rows. If you were generating a statement to run later then that might make some sense, but that isn't the case here.

Return Oracle column names in table.column format?

Is there any setting or method I can use to get Oracle to return results in <table>.<column> format? For example:
Query:
SELECT *
FROM foo f
INNER JOIN bar b
ON b.foo_id = f.id
Desired results:
F.ID F.BLAH B.ID B.FOO_ID B.BLAH
--------------------------------------------------------
1 blah 7 1 blah
2 blah 8 2 blah
3 blah 9 2 blah
The obvious solution is to individually alias each column SELECT f.id AS F_ID, ...; however, I'm needing to export some very large legacy tables (300+ columns), so using this method would cause the queries to be enormous and impractical.
There is no "option" in Oracle to do this; you may be able to find a client that allows you to do so as this is a job that would normally be done in the client; I don't know of one.
To expand upon tbone's answer you're going to have to do this dynamically. This does not mean that you have to list every column. You would use the data dictionary, specifically all_tab_columns or user_tab_columns to create your query. It would be easier to create a view with the exact definition you want so that you can re-use it if you want.
The aim is to use the fact that the columns existence is stored in a table as a string in order to create a query to use that column. As the column names and table names are stored as strings you can use string aggregation techniques to easily create a query or DDL statement that you can then manually, or dynamically, execute.
If you're using Oracle 11g Release 2 the listagg function is available to help you:
select 'create or replace view my_view as
select '
|| listagg( table_name || '.' || column_name
|| ' as '
|| substr(table_name,1,1) || '_'
|| column_name, ', ')
within group
( order by case when table_name = 'FOO' then 0 else 1 end
, column_id
)
|| ' from foo f
join bar b
on f.id = b.foo_id'
from user_tab_columns
where table_name in ('FOO','BAR')
;
Assuming this table structure:
create table foo ( id number, a number, b number, c number);
create table bar ( foo_id number, a number, b number, c number);
This single query produces the following:
create or replace view my_view as
select FOO.ID as F_ID, FOO.A as F_A, FOO.B as F_B, FOO.C as F_C
, BAR.FOO_ID as B_FOO_ID, BAR.A as B_A, BAR.B as B_B, BAR.C as B_C
from foo f
join bar b on f.id = b.foo_id
and here's a SQL Fiddle to prove it.
In you're not using 11.2 you can achieve exactly the same results using the undocumented function wm_concat or the user-defined function stragg, which was created by Tom Kyte. Oracle Base has an article on string aggregation techniques and there are many posts on Stack Overflow.
As a little addendum you can actually create exactly what you're looking for with a small change to the above query. You can use a quoted identifier to create a column in the TABLE_NAME.COLUMN_NAME format. You have to quote it as . is not a valid character for an object name in Oracle. The benefit of this is that you gain exactly what you want. The downside is that querying the created view is a huge pain if you don't use select * from ...; selecting named columns will require them to be quoted.
select 'create or replace view my_view as
select '
|| listagg( table_name || '.' || column_name
|| ' as '
|| '"' || table_name || '.'
|| column_name || '"', ', ')
within group
( order by case when table_name = 'FOO' then 0 else 1 end
, column_id
)
|| ' from foo f
join bar b
on f.id = b.foo_id'
from user_tab_columns
where table_name in ('FOO','BAR')
;
This query returns:
create or replace view my_view as
select FOO.ID as "FOO.ID", FOO.A as "FOO.A", FOO.B as "FOO.B", FOO.C as "FOO.C"
, BAR.FOO_ID as "BAR.FOO_ID", BAR.A as "BAR.A"
, BAR.B as "BAR.B", BAR.C as "BAR.C"
from foo f
join bar b on f.id = b.foo_id
Using aliases wouldn't make the queries become impractical, its just not nearly as convenient as typing *. Use dynamic SQL to generate the columns for you:
select 'f.' || column_name || ' as F_' || column_name || ','
from all_tab_columns
where table_name = 'FOO'
order by column_id;
Do the same for any other wide tables you need, and copy/paste into your query. Also note the 30 char limit, hopefully none of your columns are over 28 in size.

Resources