Finding lines where a table is inserted and updated with dba_source - sql

I want to find all insert, update , and merge lines in whole dba
what i tried:
SELECT owner, name, type,line,text
FROM dba_source where regexp_like(text,'into my_table')
union all
SELECT owner, name, type,line,text
FROM dba_source where regexp_like(text,'update my_table')
but nothing returns from my select function.
EDIT: The return must contain specific table. Return should not contain tables like "my_table_2" or "my_table_temp"

You are not using a very good method to search. You will not get any results, if the source is saved in the below way -
insert
into
any_table
Because there are multiple new lines, so your query from dba_source/all_source will fail.
A better way to find that is -
select * from dba_dependencies
where referenced_name = 'TABLE_NAME|SYNONYM_NAME'
and referenced_type = 'TABLE|SYNONYM'
Example,
suppose you have a PROCEDURE XYZ, which has the below construct
create or replace procedure xyz
begin
insert
into
any_table ....
end;
Then, if you run the below query
select * from dba_dependencies
where referenced_name = 'any_table'
and referenced_type = 'TABLE';
The result of the above query will give you 'XYZ' as a record.

As I mentioned in comments, one issue could be the case of the text. Another could be the number of white-space characters between the characters.
SELECT owner,
name,
type,
line,
text
FROM dba_source
WHERE REGEXP_LIKE(
text,
'(into|update)\s+table_name(\s|$)',
-- Match both conditions and any amount of white-space
'i' -- Case insensitive
)
You then need to deal with other case where:
The table identifier is on the next line from the INTO or UPDATE keyword;
The table identifier has a schema prefix SCHEMA_NAME.TABLE_NAME; or
The an identifier is quoted "TABLE_NAME" or "SCHEMA_NAME"."TABLE_NAME";
A combination of the above.
Which would give you an expression like:
SELECT owner,
name,
type,
line,
text
FROM dba_source
WHERE REGEXP_LIKE(
text,
'(into|update)\s+(("?)schema_name\3\.)?("?)table_name\4(\s|$)',
-- Match both conditions, schema, quotes and any amount of white-space
'i' -- Case insensitive
)
You could also use LAG or LEAD to look for statements spread across lines.

There are several things to consider:
there may be space between the keyword INSERT and the table name
there may be a schema name preceding the table name (my_schema.my_table)
the table name may be in upper or lower case or a mix of them
excluding my_table_xxx for a search on my_table, as you already mentioned
Here is a query for this:
SELECT owner, name, type, line, text
FROM dba_source
WHERE regexp_like(text, '(update|into)[[:space:]]+my_table($|\s|\W)', 'i')
OR regexp_like(text, '(update|into)[[:space:]]+[[:alpha:]]+\.my_table($|\s|\W)', 'i');
However, this still doesn't cover the case where you have INSERT in one line and the table name in the next.

Try this:-
SELECT owner, name, type,line,text
FROM dba_source where regexp_like(UPPER(text),'INTO YOUR_TABLE_NAME')
union all
SELECT owner, name, type,line,text
FROM dba_source where regexp_like(UPPER(text),'UPDATE YOUR_TABLE_NAME');

Related

How can we enter many values in a SQL parameter - SQL Developer?

In SQL Developer, we can use parameters in order to test our query with different values - for example:
I have a table called Fruits (code, name). I want to retrieve code's apples.
SELECT *
FROM fruits
WHERE name IN (:PM_NAME)
It works correctly when I fill out one value (in this case :PM_NAME equal apple)
But when I want to fill out many values it doesn't work! I've tried these forms and these separators but still..
apple;orange
'apple';'orange'
('apple','orange')
['apple','orange']
"apple","orange"
In a nutshell what's the correct format to fill out multiple values in a SQL parameter in SQL Developer ?
I can't take credit for this 'trick' but the solution lies in a regular expression.
I want to search on multiple types of objects, fed to a :bind, and used in a WHERE clause.
SELECT owner,
object_name,
object_type
FROM all_objects
WHERE object_name LIKE :SEARCH
AND owner NOT IN (
'SYS',
'MDSYS',
'DBSNMP',
'SYSTEM',
'DVSYS',
'APEX_050100',
'PUBLIC',
'ORDS_METADATA',
'APEX_LISTENER'
)
AND object_type IN (
SELECT regexp_substr(:bind_ename_comma_sep_list,'[^,]+',1,level)
FROM dual CONNECT BY
regexp_substr(:bind_ename_comma_sep_list,'[^,]+',1,level) IS NOT NULL
)
ORDER BY owner,
object_name,
object_type;
I first learned of this 'trick' or technique from here.
So your query would look like this
SELECT *
FROM fruits
WHERE name IN (
SELECT regexp_substr(:PM_NAME,'[^,]+',1,level)
FROM dual CONNECT BY
regexp_substr(:PM_NAME,'[^,]+',1,level) IS NOT NULL
)
When you're prompted for values by SQL Developer, don't quote the strings, just comma separate them. Also, no spaces.
So in the input box, enter
apple,orange
And I suppose if you want ; vs , then update the regex call as needed.

How to make WHERE clause case insensitive in oracle sql database?

select * from table_Name where name ="red"
I need to fetch both "red" and "RED".
For example: I need to use both upper and lower in same statement.
How can I do this?
You could use case insensitive parameter at session 'NLS_SORT=BINARY_CI'. There are two parameters at session level:
NLS_COMP
NLS_SORT
Let's see a demo:
Normal scenario:
SQL> with names as
(
select 'Vishnu' name from dual
)
-- Your query starts here
select * from names where name='vIsHnU';
no rows selected
Case insensitive approach:
SQL> alter session set nls_comp='LINGUISTIC';
Session altered
SQL> alter session set nls_sort='BINARY_CI';
Session altered
SQL> with names as
(
select 'Vishnu' name from dual
)
-- Your query starts here
select * from names where name='vIsHnU';
NAME
------
Vishnu
One more example:
SQL> with names as
(
select 'red' name from dual union all
select 'RED' from dual
)
-- Your query starts here
select * from names where name='rEd';
NAME
----
red
RED
To improve the performance, you could also create a case insensitive INDEX.
For example:
create index names_ci_indx on names(NLSSORT(name,'NLS_SORT=BINARY_CI'));
Now, there are ways to improve performance of above transaction. Please read Oracle – Case Insensitive Sorts & Compares
select * from table_Name where lower(name) ="red"
or
select * from table_Name where upper(name) ="RED"
This cannot use an index on name. It might be appropriate to create a function based index on the expression used.

How to run a single query over all the tables in a user schema in ORACLE

Let say I have tables A,B,C,......,Z and I want to count all the entries in the tables and combine the results like so:
SELECT 'A' AS A, count(*) from USER.A UNION
.
.
.
SELECT 'J' AS J, count(*) from USER.J UNION
.
.
SELECT 'Z' AS 'Z' COUNT(*) from USER.Z
I want to avoid all above hassle. How can I do this in a smart way?.
I tend to do this by writing a query using the user_tables Meta information View and first time selecting text that is actually an sql query:
SELECT 'select '''||TABLE_NAME||''', count(*) from '||TABLE_NAME||'union all' FROM USER_TABLES
Running that in your query tool will produce a grid of rows that are actually sql queries in their own right. Copying them out of the results grid, pasting them into the query window (remove the trailing UNION ALL) and running them again produces data for each table
select 'a', count(*) from a union all
select 'b', count(*) from b union all ....
To get more involved and include column names, there's a USER_TAB_COLUMNS view that cites info about columns (e.g. You could write a query that generates queries that search any varchar columns for a particular value)
If you get really involved it can be cleaner to use placeholders in the string and REPLACE them:
SELECT REPLACE(REPLACE(REPLACE(
'select ''{o}.{t}'' as tname, ''{c}'' as cname
from {o}.{t} where
{c} like ''hello%'' or
{c} like ''goodbye%'' union all'
--to add more placeholders copy paste these lines
--and ensure there is the same number of REPLACE
--as there are numbers of lines
, '{t}', TABLE_NAME)
, '{c}', COLUMN_NAME)
, '{o}', OWNER)
FROM ALL_TAB_COLUMNS
WHERE DATA_TYPE = 'VARCHAR'
This is massively cleaner than starting and stopping your string all the time with || concatenation. I've deliberately uppercase the outer query and lowercase the inner query so you can tell which part is which
To add more placeholders, put additional REPLACE( at the top and copy paste in place the lines underneath that begin with a comma. Example copy , '{t}', table_name) paste and change to , '{d}', data_type) add another REPLACE( at the top and now you have a {d} placeholder you can use anywhere in the first string (the sql query pattern) to signify the data type

Is the 'as' keyword required in Oracle to define an alias?

Is the 'AS' keyword required in Oracle to define an alias name for a column in a SELECT statement?
I noticed that
SELECT column_name AS "alias"
is the same as
SELECT column_name "alias"
I am wondering what the consequences are of defining a column alias in the latter way.
According to the select_list Oracle select documentation the AS is optional.
As a personal note I think it is easier to read with the AS
(Tested on Oracle 11g)
About AS:
When used on result column, AS is optional.
When used on table name, AS shouldn't be added, otherwise it's an error.
About double quote:
It's optional & valid for both result column & table name.
e.g
-- 'AS' is optional for result column
select (1+1) as result from dual;
select (1+1) result from dual;
-- 'AS' shouldn't be used for table name
select 'hi' from dual d;
-- Adding double quotes for alias name is optional, but valid for both result column & table name,
select (1+1) as "result" from dual;
select (1+1) "result" from dual;
select 'hi' from dual "d";
AS without double quotations is good.
SELECT employee_id,department_id AS department
FROM employees
order by department
--ok--
SELECT employee_id,department_id AS "department"
FROM employees
order by department
--error on oracle--
so better to use AS without double quotation if you use ORDER BY clause
Both are correct. Oracle allows the use of both.
My conclusion is that(Tested on 12c):
AS is always optional, either with or without ""; AS makes no difference (column alias only, you can not use AS preceding table alias)
However, with or without "" does make difference because "" lets lower case possible for an alias
thus :
SELECT {T / t} FROM (SELECT 1 AS T FROM DUAL); -- Correct
SELECT "tEST" FROM (SELECT 1 AS "tEST" FROM DUAL); -- Correct
SELECT {"TEST" / tEST} FROM (SELECT 1 AS "tEST" FROM DUAL ); -- Incorrect
SELECT test_value AS "doggy" FROM test ORDER BY "doggy"; --Correct
SELECT test_value AS "doggy" FROM test WHERE "doggy" IS NOT NULL; --You can not do this, column alias not supported in WHERE & HAVING
SELECT * FROM test "doggy" WHERE "doggy".test_value IS NOT NULL; -- Do not use AS preceding table alias
So, the reason why USING AS AND "" causes problem is NOT AS
Note: "" double quotes are required if alias contains space OR if it contains lower-case characters and MUST show-up in Result set as lower-case chars. In all other scenarios its OPTIONAL and can be ignored.
The quotes are required when we have a space in Alias Name like
SELECT employee_id,department_id AS "Department ID"
FROM employees
order by department
There is no difference between both, AS is just a more explicit way of mentioning the alias which is good because some dependent libraries depends on this small keyword. e.g. JDBC 4.0. Depend on use of it, different behaviour can be observed.
See this. I would always suggest to use the full form of semantic to avoid such issues.

Inline table in Oracle SQL

I'm trying to integrate with some software (that I can't modify) that queries a database that I can modify.
I can give this software SQL queries, like so "select username, firstname, lastname from users where username in ?"
The software than fills in the ? with something like ('alice', 'bob'), and gets user information for them.
Thing is, there's another piece of software, which I again can't modify, which occasionally generates users like 'user2343290' and feeds them through to the first piece of software. Of course, it throws errors because it can't find that user.
So the query I want to run is something like this:
select username, firstname, lastname from users where username in ?
UNION ALL
select t.column1, 'Unknown', 'Unknown' from create_table(?) t
where create_table generates a table with the rows mentioned in ?, with the first column named column1.
Or alternatively:
select username, firstname, lastname from users where username in ?
UNION ALL
select t.column1, 'Unknown', 'Unknown' from _universe_ t where t.column1 in ?
where _universe_ is some fake table that contains possible every value in column1 (i.e. infinitely large).
I've tried select ? from dual, but unfortunately this only worked when ? was something like ('x'), not ('x', 'y').
Keep in mind I can't change the format of how the ? comes out, so I can't do select 'alice' from dual union all select 'bob' from dual.
Anyone know how I could do what I've mentioned, or something else to have a similar effect?
You can turn the delimited string of names into a table type like so:
CREATE TYPE name_tab AS TABLE OF VARCHAR2(30);
/
SELECT * FROM table(name_tab('alice','bob'));
So you would just need to create the type then your example would become:
select username, firstname, lastname from users where username in ?
UNION ALL
select t.column1, 'Unknown', 'Unknown' from table(name_tab ?) t
(I'm assuming that the ? is replaced by simple text substitution -- because the IN wouldn't work if it was done as a bind variable -- and that the substituted text includes the parentheses.)
However, I am not sure the result of this will be helpful, since when a list of good usernames is given, you'll now have two result rows for each username, one with the actual information and another with the 'Unknown' values.
A better way to phrase the query might be:
select t.column_value username,
NVL(users.firstname,'Unknown'),
NVL(users.lastname,'Unknown')
from table(name_tab ?) t left join users on users.username = t.column_value
That should give you one row per username, with the actual data if it exists, or the 'Unknown' values if it does not.
You could use a pipelined function:
create type empname_t is table of varchar2(100);
create or replace function to_list(p_Names in string) return empname_t pipelined is
begin
pipe row(p_Names);
return;
end;
select * from table(to_list('bob'))
If you need to split the names (e.g. 'bob,alice'), you could use a function accepting a string and returning a empname_t, e.g. Tom Kyte's in_list, see
http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:210612357425
and modify the to_list function to iterate over the collection and pipe each item from the collection.