How to find the exact table names in the user Query in Oracle SQL? - sql

In Oracle SQL developer I have a Query in which I have to find all the table names which are starting as 'DIM' and 'FCT' and 'ABC'.
Example:
SELECT * FROM DIM_TABLE,fct_table,abc_table WHERE..
I am trying through regular expression instring and substring.But unable to get the exact end position of the table.
Can you please help me in this?

My approach is as follows:
a. first extract the part of the query that contains table names separated by comma
b. convert comma separated values to rows
c. Filter out the rows by the criteria given
select * from(
select trim(regexp_substr(REGEXP_SUBSTR('SELECT * FROM DIM_TABLE,fct_table,abc_table WHERE','FROM (.*) WHERE',1,1,null,1),'[^,]+', 1, level) ) value, level
from dual
connect by regexp_substr(REGEXP_SUBSTR('SELECT * FROM DIM_TABLE,fct_table,abc_table WHERE','FROM (.*) WHERE',1,1,null,1), '[^,]+', 1, level) is not null
)
where
value like 'DIM%' or value like 'fct%' or value like 'abc%'
results:
DIM_TABLE
fct_table
abc_table
EDIT 2:
ok
So now that you have changed your original query this will look like the following:
select * from(
select trim(regexp_substr(
replace (
replace (
replace (
REGEXP_SUBSTR('SELECT * FROM DIM_TABLE INNER JOIN FCT_TABLE ON FCT_TABLE.COL1 = DIM_TABLE.COL1 LEFT OUTER JOIN ABC_TABLE WHERE','FROM (.*) WHERE',1,1,null,1),
'INNER JOIN',',') ,'LEFT OUTER JOIN',','), 'ON',',XXX')
,'[^,]+', 1, level) ) value, level
from dual
connect by regexp_substr(
replace (
replace (
replace (
REGEXP_SUBSTR('SELECT * FROM DIM_TABLE INNER JOIN FCT_TABLE ON FCT_TABLE.COL1 = DIM_TABLE.COL1 LEFT OUTER JOIN ABC_TABLE WHERE','FROM (.*) WHERE',1,1,null,1),
'INNER JOIN',',') ,'LEFT OUTER JOIN',','), 'ON',',XXX')
, '[^,]+', 1, level) is not null
)
where
value like 'DIM%' or value like 'FCT%' or value like 'ABC%'
Results 2
DIM_TABLE 1
FCT_TABLE 2
ABC_TABLE 4
It is not pretty - but it works - I think you got the idea...

SELECT table_name
FROM user_tables
WHERE table_name like 'DIM%'
OR table_name like 'FCT%'
OR table_name like 'ABC%'

Related

How to fin and extract substring BIGQUERY

A have a string column at BigQuery table for example:
name
WW_for_all_feed
EU_param_1_for_all_feed
AU_for_all_full_settings_18+
WW_for_us_param_5_for_us_feed
WW_for_us_param_5_feed
WW_for_all_25+
and also have a list of variables, for example :
param_1_for_all
param_5_for_us
param_5
full_settings
And if string at column "name" contains one of this substrings needs to extract it :
name
param
WW_for_all_feed
None
EU_param_1_for_all_feed
param_1_for_all
AU_for_all_full_settings_18+
full_settings
WW_for_us_param_5_for_us_feed
param_5_for_us
WW_for_us_param_5_feed
param_5
WW_for_all_25+
None
I want to try regexp and replace, but don't know pattern for find substring
Use below
select name, param
from your_table
left join params
on regexp_contains(name, param)
if apply to sample data as in your question
with your_table as (
select 'WW_for_all_feed' name union all
select 'EU_param_1_for_all_feed' union all
select 'AU_for_all_full_settings_18+' union all
select 'WW_for_us_param_5_for_us_feed' union all
select 'WW_for_all_25+'
), params as (
select 'param_1_for_all' param union all
select 'param_5_for_us' union all
select 'full_settings'
)
output is
but I have an another issue (updated question) If one of params is substring for another?
use below then
select name, string_agg(param order by length(param) desc limit 1) param
from your_table
left join params
on regexp_contains(name, param)
group by name
if applied to your updated data sample - output is

How to pass multiple string values through bind variable by comma separated oracle sql

SELECT a.gl_account, g.gl
from et_bp_gl_account a,et_bp_gl g
where a.gl_id=g.gl_id
and g.gl in (select replace(:P117_GL,':',',') from et_bp_gl )
----- Here is the code that I use to pass multiple values through the bind variable like that (Asset Mg:Finance) the subquery supposed to return (Asset Mg,Finance) by replacing ':' by ',' but it doesn't work and returns
no date found
Using Oracle Sql
Apex, eh? That's either a shuttle item or a select item that allows multiple selection. Anyway, you should split that colon-separated list into rows, something like this:
SELECT a.gl_account, g.gl
from et_bp_gl_account a,et_bp_gl g
where a.gl_id=g.gl_id
and g.gl in (select regexp_substr(:P117_GL, '[^:]+', 1, level)
from dual
connect by level <= regexp_count(:P117_GL, ':') + 1
)
No need for regular expression
select * from table(apex_string.split('1:2:3',':'));
So your query might look like
SELECT a.gl_account, g.gl
from et_bp_gl_account a,et_bp_gl g
where a.gl_id=g.gl_id
and g.gl in (select column_value
from table(apex_string.split(:P117_GL,':'))
)
It wouldn't surprise me if this could be simplified further

SQL Search rows that contain strings from 2nd table list

I have a master table that contains a list of strings to search for. it returns TRUE/FALSE if any string in the cell contains text from the master lookup table. Currently I use excel's
=SUMPRODUCT(--ISNUMBER(SEARCH(masterTable,[#searchString])))>0
is there a way to do something like this in SQL? LEFT JOIN or OUTER APPLY would be simple solutions if the strings were equal; but they need be contains..
SELECT *
FROM t
WHERE col1 contains(lookupString,lookupColumn)
--that 2nd table could be maintained and referenced from multiple queries
hop
bell
PRS
2017
My desired results would be a column that shows TRUE/FALSE if the row contains any string from the lookup table
SEARCH_STRING Contained_in_lookup_column
hopping TRUE
root FALSE
Job2017 TRUE
PRS_tool TRUE
hand FALSE
Sorry i dont have access to the DB now to confirm the syntax, but should be something like this:
SELECT t.name,
case when (select count(1) from data_table where data_col like '%' || t.name || '%' > 0) then 'TRUE' else 'FALSE' end
FROM t;
or
SELECT t.name,
case when exists(select null from data_table where data_col like '%' || t.name || '%') then 'TRUE' else 'FALSE' end
FROM t;
Sérgio
You can use a combination of % wildcards with LIKE and EXISTS.
Example (using Oracle syntax) - we have a v_data table containing the data and a v_queries table containing the query terms:
with v_data (pk, value) as (
select 1, 'The quick brown fox jumps over the lazy dog' from dual union all
select 2, 'Yabba dabba doo' from dual union all
select 3, 'forty-two' from dual
),
v_queries (text) as (
select 'quick' from dual union all
select 'forty' from dual
)
select * from v_data d
where exists (
select null
from v_queries q
where d.value like '%' || q.text || '%');

Oracle 'where clause' to become shorter

Lets assume 'table1' has three columns:
'key',
'singleID',
'multipleIDs'
Rows would be like:
1,'8736', '1234;6754;9785;6749'
2,'7446', '9959;7758;6485;9264'
To search for all rows which have an id either in 'singleID' or as part of
the concatenated IDs in the 'multipleIDs' I would:
select key from table1 where
singleID = '8888' or multipleIDs like '%8888%';
When searching not only for one ID (8888) like in this statement but for 100 it would be necessary to repeate the where clause 100 times with different id like:
select key from table1 where
singleID = '8888' or multipleIDs like '%8888%' or
singleID = '9999' or multipleIDs like '%9999%' or
....;
The IDs to search for are taken dynamically from another query like
select id from table2;
The query shall
be created dynamically since the number of IDs might vary.
Like this the SQL statement would become quite long.
Is there a nice and short way to express that in Oracle SQL? PLSQL perhaps?
Something like this?
This is the test version:
with sv_qry
as
(
SELECT trim(regexp_substr(search_values, '[^,]+', 1, LEVEL)) val
FROM (select '1234,7446' as search_values
from dual
)
CONNECT BY LEVEL <= regexp_count(search_values, ',')+1
)
, table1_qry
as
(select 1 as id,'8736' as single_id, '1234;6754;9785;6749' as multiple_id from dual
union all
select 2,'7446' as single_id, '9959;7758;6485;9264' as multiple_id from dual
)
select *
from table1_qry
inner join
sv_qry
on single_id = val or multiple_id like '%'||val||'%'
And this would be with a table called table1:
with sv_qry
as
(
SELECT trim(regexp_substr(search_values, '[^,]+', 1, LEVEL)) val
FROM (select '1234,7446' as search_values
from dual
)
CONNECT BY LEVEL <= regexp_count(search_values, ',')+1
)
select *
from table1
inner join
sv_qry
on single_id = val or multiple_id like '%'||val||'%'
Partial credit goes here:
Splitting string into multiple rows in Oracle
You can express the query like this :
select key
from table1 a
join ( select id from table2 where id in ('yyyy','xxxx','zzzz',...) b
on a.singleId = b.id or a.multipleID like '%'||b.id||'%';

Select where record does not exists

I am trying out my hands on oracle 11g. I have a requirement such that I want to fetch those id from list which does not exists in table.
For example:
SELECT * FROM STOCK
where item_id in ('1','2'); // Return those records where result is null
I mean if item_id '1' is not present in db then the query should return me 1.
How can I achieve this?
You need to store the values in some sort of "table". Then you can use left join or not exists or something similar:
with ids as (
select 1 as id from dual union all
select 2 from dual
)
select ids.id
from ids
where not exists (select 1 from stock s where s.item_id = ids.id);
You can use a LEFT JOIN to an in-line table that contains the values to be searched:
SELECT t1.val
FROM (
SELECT '1' val UNION ALL SELECT '2'
) t1
LEFT JOIN STOCK t2 ON t1.val = t2.item_id
WHERE t2.item_id IS NULL
First create the list of possible IDs (e.g. 0 to 99 in below query). You can use a recursive cte for this. Then select these IDs and remove the IDs already present in the table from the result:
with possible_ids(id) as
(
select 0 as id from dual
union all
select id + 1 as id from possible_ids where id < 99
)
select id from possible_ids
minus
select item_id from stock;
A primary concern of the OP seems to be a terse notation of the query, notably the set of values to test for. The straightforwwrd recommendation would be to retrieve these values by another query or to generate them as a union of queries from the dual table (see the other answers for this).
The following alternative solution allows for a verbatim specification of the test values under the following conditions:
There is a character that does not occur in any of the test values provided ( in the example that will be - )
The number of values to test stays well below 2000 (to be precise, the list of values plus separators must be written as a varchar2 literal, which imposes the length limit ). However, this should not be an actual concern - If the test involves lists of hundreds of ids, these lists should definitely be retrieved froma table/view.
Caveat
Whether this method is worth the hassle ( not to mention potential performance impacts ) is questionable, imho.
Solution
The test values will be provided as a single varchar2 literal with - separating the values which is as terse as the specification as a list argument to the IN operator. The string starts and ends with -.
'-1-2-3-156-489-4654648-'
The number of items is computed as follows:
select cond, regexp_count ( cond, '[-]' ) - 1 cnt_items from (select '-1-2-3-156-489-4654648-' cond from dual)
A list of integers up to the number of items starting with 1 can be generated using the LEVEL pseudocolumn from hierarchical queries:
select level from dual connect by level < 42;
The n-th integer from that list will serve to extract the n-th value from the string (exemplified for the 4th value) :
select substr ( cond, instr(cond,'-', 1, 4 )+1, instr(cond,'-', 1, 4+1 ) - instr(cond,'-', 1, 4 ) - 1 ) si from (select cond, regexp_count ( cond, '[-]' ) - 1 cnt_items from (select '-1-2-3-156-489-4654648-' cond from dual) );
The non-existent stock ids are generated by subtracting the set of stock ids from the set of values. Putting it all together:
select substr ( cond, instr(cond,'-',1,level )+1, instr(cond,'-',1,level+1 ) - instr(cond,'-',1,level ) - 1 ) si
from (
select cond
, regexp_count ( cond, '[-]' ) - 1 cnt_items
from (
select '-1-2-3-156-489-4654648-' cond from dual
)
)
connect by level <= cnt_items + 1
minus
select item_id from stock
;