Am having a table with 30+ columns. Would like to append all the column data.
I'm currently using multiple concatenate operators to achieve this in Oracle.
Example :
SELECT C1.data || '' || C2.data ||..........Cm.data
FROM C
Is there any other way of doing it with out using the '||' - concatenate operator multiple times ? I want to achieve this using query. (Not interested in post processing using any language) Any assistance would be of great help.
Try something like this. Anyway you'll be mentioning all the columns you needed.
declare
stmt varchar2(300);
v_char char(10):=',||" "||,';
begin
stmt:='select 1,2,3,4 from tab';
dbms_output.put_line(stmt);
select replace(stmt,',',v_char) into stmt from dual;
dbms_output.put_line(stmt);
execute immediate stmt; // you can add this after verifying your query
end;
OUTPUT:
select 1,||" "||, 2,||" "||, 3,||" "||, 4 from tab;
Related
This question already has answers here:
Querying an Oracle Database with Dynamic Table names
(1 answer)
dynamic table name without using cursors
(1 answer)
dynamic table name in cursor
(2 answers)
dynamic table name in select statement
(4 answers)
Closed 2 years ago.
without going into details - the tools we use for performance test, it spits out several tables (name changes with every new run) with different type of data. One table has list of all the table names and data type.
I am going to use oracle table as an example so it can be easily explained.
What I am wanting to do...
Query all_table like:
QueryA:
select table_name from all_tables where table_name like 'HZ_CUST_%'
Result will say: Table_name = 'HZ_CUST_ACCOUNTS'
Query using the QueryA result like:
Select * from [QUERYA_RESULT] WHERE creation_date > sysdate, account_number between '500000' and '599999'
I got something like this but not quite sure how to do this.
declare variable TABLE_NAME CHAR(10);
SELECT TABLE_NAME into :V_NAME from all_tables WHERE TABLE_NAME LIKE 'HZ_CUST_ACCOUNTS';
select *
from :V_NAME;
Thank you for the help.
The easiest solution for your problem given what you have expressed in the comment section is to use DYNAMIC SQL
declare
v_table_name varchar2(130);
v_sql clob;
begin
-- get the table name
select table_name into v_table_name from all_tables where table_name like 'HZ_CUST_%' ;
-- Build dynamic statement
v_sql := ' select * from '||v_table_name||' where creation_date > sysdate
and account_number between ''500000'' and ''599999'' ';
execute immediate v_sql;
end;
/
From this small version, you can expand this code to whatever you need to do, specialy with the output. Of course, depending on what you need to do with it. I could for example store the maximum value of a field based on this same sentence.
declare
v_table_name varchar2(130);
v_sql clob;
vmaxvalue pls_integer;
begin
-- get the table name
select table_name into v_table_name from all_tables where table_name like 'HZ_CUST_%' ;
-- Build dynamic statement
v_sql := ' select max(table_field) from '||v_table_name||' where creation_date > sysdate
and account_number between ''500000'' and ''599999'' ';
execute immediate v_sql into vmaxvalue;
end;
/
I don't believe you need for your case to use PTF ( Polymorphic Table Functions ) which are intended to evolve the concept of pipeline functions. However, as you did explain very well what you intent to do with the result of the query, you might want to have a look at them. Check this very good example of PTF ( Remember Oracle 18c or higher ).
Polymorphic Table Functions
I am trying to derive a table with counts from multiple tables. The tables are not on my schema. The table names on the schema that I am interested in all start with 'STAF_' and end with '_TS'. The criteria i am looking for is where SEP = 'MO'. So for example, the query in its base form is:
select area, count(SEP) areacount
from mous.STAF_0001_TS
where SEP = 'MO'
group by area;
I have about 1000 tables that i'd like to do this for.
Ultimatly, I'd like the output to be a table on my schema that looks like the following:
area| areacount
0001| 3
0002| 7
0003| 438
Thank you.
As a first step I'd write an SQL query that generates an SQL query:
SELECT 'SELECT area, count(*) FROM '||c.table_name||'UNION ALL' as run_me
FROM all_tables c
WHERE c.table_name LIKE 'STAF\_%\_MS' escape '\'
Running this will produce an output that is another SQL query. Copy the result text out of your results grid and paste it back into your query pane. Delete the final UNION ALL and run it
Once you dig how to write an SQL query that generate an SQL query, you can look at turning it into a view, or creating a dynamic query in a string.
Gotta say, this is a horrible way to store data; you'd be better off using ONE table with an extra column containing whatever is in xxx of STAF_xxx_MS right now
In Oracle 12c, you can embed a FUNCTION that will query the number of rows in any given table. Then you can use that function in your main query. Here is an example:
WITH FUNCTION cnt ( p_owner VARCHAR2, p_table_name VARCHAR2 ) RETURN NUMBER IS
l_cnt NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT count(*) INTO :cnt FROM ' || p_owner || '.' || p_table_name INTO l_cnt;
RETURN l_cnt;
EXCEPTION WHEN OTHERS THEN
RETURN NULL; -- This will happen for entries in ALL_TABLES that are not directly accessible (e.g., IOT overflow tables)
END cnt;
SELECT t.owner, t.table_name, cnt(t.owner, t.table_name)
FROM all_tables t
where t.table_Name like 'STAF\_%\_MS' escape '\';
I am running same query for different values. Such as I am querying the table for aa, bb, cc, dd, ee ... Is there any way like as function and use parameters rather than duplication my codes 10 times only for one variable changes.
I am pretty new, and don't know what to name of my solution. I do appreciate any ideas, or let me know if you need more details.
I am using toad for oracle, and need oracle sql solution.
You can write a simple query like this
select * from table where value in ('aa','bb','cc','dd','ee')
IF need to function you can use below sample :
FUNCTION GET_values( Any arguments to that query)
RETURN VARCHAR2
IS
BEGIN
SELECT value
INTO v_value
FROM table
WHERE condition;
RETURN v_value;
END GET_values;
You can use a cursor for the solution.
declare
cursor c1(value1 varchar) is
select columns from tab1
where column1= value1;
l_columns varchar2;
begin
OPEN c1(aa);
fetch c1 into l_columns ;
close c1;
end;
I have a SQL sentence where I make a minus of two tables to search the differences. As I use frequently I would like to create a function or procedure to make these and get output by screen. Someone could explain me how is the best way to make these, could you put me some example?
If you frequently use the MINUS query, then it is better to create a view on the query. To fetch the resultset, you just need to select from the view.
For example,
CREATE OR REPLACE VIEW my_view AS
SELECT column_list FROM table1
MINUS
SELECT column_list FROM table2
And to fetch the result,
SELECT * FROM my_view;
Read the documentation for more details on CREATE VIEW
Maybe this is the what you're looking for, if you're using Oracle 11g Release 2:
create or replace procedure prnt_my_view(my_view in varchar2, separator in varchar2 default ',') is
type myrefcur is ref cursor;
type rowtext is table of varchar2(256);
rowdef varchar2(256);
rows_cv myrefcur;
text rowtext;
begin
select listagg(column_name,'||'''||separator||'''||') within group (order by column_id) into rowdef from user_tab_columns where lower(table_name) = lower(my_view);
open rows_cv for 'select '||rowdef||' from '||my_view;
fetch rows_cv bulk collect into text;
for i in text.first..text.last loop
dbms_output.put_line(text(i));
end loop;
close rows_cv;
exception when others then
dbms_output.put_line('something is wrong:'||sqlerrm);
end;
edit:
if you can't use listagg, check other solutions for example here: alternative to listagg in Oracle?
I have 2 procedures inside a package. I am calling one procedure to get a comma separated list of user ids.
I am storing the result in a VARCHAR variable. Now when I am using this comma separated list to put inside an IN clause in it is throwing "ORA-01722:INVALID NUMBER" exception.
This is how my variable looks like
l_userIds VARCHAR2(4000) := null;
This is where i am assigning the value
l_userIds := getUserIds(deptId); -- this returns a comma separated list
And my second query is like -
select * from users_Table where user_id in (l_userIds);
If I run this query I get INVALID NUMBER error.
Can someone help here.
Do you really need to return a comma-separated list? It would generally be much better to declare a collection type
CREATE TYPE num_table
AS TABLE OF NUMBER;
Declare a function that returns an instance of this collection
CREATE OR REPLACE FUNCTION get_nums
RETURN num_table
IS
l_nums num_table := num_table();
BEGIN
for i in 1 .. 10
loop
l_nums.extend;
l_nums(i) := i*2;
end loop;
END;
and then use that collection in your query
SELECT *
FROM users_table
WHERE user_id IN (SELECT * FROM TABLE( l_nums ));
It is possible to use dynamic SQL as well (which #Sebas demonstrates). The downside to that, however, is that every call to the procedure will generate a new SQL statement that needs to be parsed again before it is executed. It also puts pressure on the library cache which can cause Oracle to purge lots of other reusable SQL statements which can create lots of other performance problems.
You can search the list using like instead of in:
select *
from users_Table
where ','||l_userIds||',' like '%,'||cast(user_id as varchar2(255))||',%';
This has the virtue of simplicity (no additional functions or dynamic SQL). However, it does preclude the use of indexes on user_id. For a smallish table this shouldn't be a problem.
The problem is that oracle does not interprete the VARCHAR2 string you're passing as a sequence of numbers, it is just a string.
A solution is to make the whole query a string (VARCHAR2) and then execute it so the engine knows he has to translate the content:
DECLARE
TYPE T_UT IS TABLE OF users_Table%ROWTYPE;
aVar T_UT;
BEGIN
EXECUTE IMMEDIATE 'select * from users_Table where user_id in (' || l_userIds || ')' INTO aVar;
...
END;
A more complex but also elegant solution would be to split the string into a table TYPE and use it casted directly into the query. See what Tom thinks about it.
DO NOT USE THIS SOLUTION!
Firstly, I wanted to delete it, but I think, it might be informative for someone to see such a bad solution. Using dynamic SQL like this causes multiple execution plans creation - 1 execution plan per 1 set of data in IN clause, because there is no binding used and for the DB, every query is a different one (SGA gets filled with lots of very similar execution plans, every time the query is run with a different parameter, more memory is needlessly used in SGA).
Wanted to write another answer using Dynamic SQL more properly (with binding variables), but Justin Cave's answer is the best, anyway.
You might also wanna try REF CURSOR (haven't tried that exact code myself, might need some little tweaks):
DECLARE
deptId NUMBER := 2;
l_userIds VARCHAR2(2000) := getUserIds(deptId);
TYPE t_my_ref_cursor IS REF CURSOR;
c_cursor t_my_ref_cursor;
l_row users_Table%ROWTYPE;
l_query VARCHAR2(5000);
BEGIN
l_query := 'SELECT * FROM users_Table WHERE user_id IN ('|| l_userIds ||')';
OPEN c_cursor FOR l_query;
FETCH c_cursor INTO l_row;
WHILE c_cursor%FOUND
LOOP
-- do something with your row
FETCH c_cursor INTO l_row;
END LOOP;
END;
/