Display column based on certain condition - sql

I want to display column based on certain condition, is it possible for that as i do this getting an error.
select (
select column_name
from all_tab_cols
where table_name='BED_2016_MAR_CIT4114A_FYP1_G_'
and column_name like '%na%'
)
from BED_2016_MAR_CIT4114A_FYP1_G_;

A SQL query must list the columns it is using explicitly. You can do what you want using dynamic SQL (execute immediate). For example:
declare
sql varchar2(4000);
cols varchar2(4000);
begin
select listagg(column_name, ',') within group (order by column_name)
into cols
from all_tab_cols
where table_name = 'BED_2016_MAR_CIT4114A_FYP1_G_' and column_name like '%na%' ;
sql := '
create table newtab as
select #cols
from BED_2016_MAR_CIT4114A_FYP1_G_';
sql := replace(sql, '#cols', cols);
execute immediate sql;
end;
select *
from newtab;

Looks like the problem is in the where condition:
where table_name='BED_2016_MAR_CIT4114A_FYP1_G_'
and column_name like '%na%'
Remove the condition for table_name. You are already selecting from BED_2016_MAR_CIT4114A_FYP1_G_ so only columns in that table will be shown.
Here is a more simplified version of the query:
select column_name
from BED_2016_MAR_CIT4114A_FYP1_G_
where column_name like '%na%'
Hope that helped

Related

Select common columns from two tables

I have two tables
temp_data_holder
temp_data_holder1
These two tables will have some common columns but they can also have some extra columns which might be present in only one table. I need a query which will select the common columns from each table.
I can get the common column names using the following query
Select column_name
from all_tab_columns
where table_name like 'temp_data_holder'
intersect
Select column_name
from all_tab_columns
where table_name like 'temp_data_holder1';
Is there a way to use this query to get the resultant columns from each table?
I'm asking for something like this
Select columns=(Select column_name from all_tab_columns where table_name like 'temp_data_holder' intersect Select column_name from all_tab_columns where table_name like 'temp_data_holder1') from temp_data_holder;
I.e. the tables will be inside a for loop and the structure will change after each iteration so i cannot simply hard-code the column names
In general you can get the common columns (evaluated by name) from two tables using the statement below.
select listagg(column_name,',') within group (order by column_name)
from (
select column_name
from user_tab_columns
where table_name in (t1,t2)
group by column_name having count(*) = 2
);
the resulting string could be used to generate useful statements for comparing the two tables t1 and t2
SQL and PL/SQL are strongly-typed and rigorous languages. Doing things on the fly is hard. That makes applications reliable but developers schooled in more reflexive languages butt up against such inflexibility.
Which is to say there is no easy way to achieve what you want. You need to assemble the query as a string and use Dynamic SQL to execute the finished statement. You also will have problems reading the result set, because SQL doesn't handle ad hoc projections. Usually this means code has to be called from say Java using a Ref Cursor to map to a JDBC ResultSet.
create or replace function get_data_for_common_cols return sys_refcursor is
stmt varchar2(32767) := 'select ';
rc sys_refcursor;
begin
for recs in ( select t.column_name
, row_number() over (partition by t.table_name order by t.column_id) as rn
from user_tab_columns t
join user_tab_columns t1 on t1.column_name = t.column_name
where t.table_name = 'TEMP_DATA_HOLDER'
and t1.table_name = 'TEMP_DATA_HOLDER1'
order by t.column_id)
loop
if recs.rn != 1 then
stmt := stmt || ',';
end if;
stmt := stmt || recs.column_name;
end loop;
stmt := stmt || ' from TEMP_DATA_HOLDER';
open rc for stmt;
return rc;
end;
/
This function can be parameterised to take a table name - or two table names - for use in the loop query and the assembled statement. Doing so is left as an exercise for the reader :)
SELECT COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME IN ('articles', 'articles')
GROUP BY column_name HAVING COUNT(*) = 2;

Select entries of columns that are a certain format in SQL

I want to select/display the columns of a table that are of a certain format. I wrote the following query:
SELECT
(SELECT
COLUMN_NAME
FROM SYS.ALL_TAB_COLS
WHERE TABLE_NAME='SOME_TABLE' AND DATA_TYPE IN ('DATE'))
FROM SOME_TABLE;
After the query runs for some time, I get the following error:
ORA-01427: single-row subquery returns more than one row
I would want a result that is something like:
DATE1 DATE2
2017-01-01 2017-01-01
2017-01-01 2018-01-02
... ...
Does someone know how to achieve this?
You could make use of a refcursor bind variable and use the PRINT command to display the output from a dynamic query. This works in SQL* Plus and in Toad and SQL developer when run as script.
VARIABLE x refcursor;
DECLARE
v_query CLOB;
BEGIN
SELECT 'SELECT '
|| LISTAGG(column_name, ',')
within GROUP ( ORDER BY column_name )
|| ' FROM '
|| table_name
INTO v_query
FROM sys.all_tab_cols
WHERE table_name = 'EMPLOYEES'
AND data_type IN ( 'DATE' )
GROUP BY table_name;
OPEN :x FOR v_query;
END;
/
PRINT x;
for 12c and above, you could use DBMS_SQL.RETURN_RESULT on a PL/SQL cursor on the same query.
DECLARE
v_query CLOB;
x SYS_REFCURSOR;
BEGIN
SELECT..
..
OPEN x FOR v_query;
DBMS_SQL.RETURN_RESULT(x);
END;
/
Note: If there are multiple tables in different schemas with the same name, you would need to add owner = <schema> as well.
Use this query to return the rows in columns and then you can use and format the columns that dynamically return with execute of EXECUTE IMMEDIATE
SELECT LISTAGG(COLUMN_NAME, ',') WITHIN GROUP(ORDER BY COLUMN_NAME) AS COLUMNA FROM (
SELECT COLUMN_NAME
FROM SYS.ALL_TAB_COLS
WHERE TABLE_NAME = 'SOME_TABLE' AND DATA_TYPE IN ('DATE')
) SOME_TABLE
RESULT:
DATE1, DATE2

pivot does not work when using a nested select in SQL

I have a requirement to pivot the columns of a particular table specified from a user.
the problem is the number of columns from each table to pivot is dynamic.
so the code below gets the name of the columns from the table.
SELECT DISTINCT
LISTAGG('''' || column_name || '''', ',')
WITHIN GROUP (ORDER BY column_name) AS temp_in_statement
FROM (SELECT DISTINCT column_name FROM all_tab_columns WHERE table_name = 'DIM_XYZ')
the code above returns the columns in the following format:
col1, col2
I have to use a pivot for this requirement and plug the code above in the code below in order to pivot the columns.
SELECT * FROM
(
SELECT table_name, column_name
FROM ALL_TAB_COLUMNS
WHERE
table_name = 'DIM_XYZ'
)
PIVOT
(
MIN(column_name)
FOR column_name IN (
-- values added manually
'col1','col2'
-- values added manually
)
)
ORDER BY table_name;
The code works fine in this case but when replacing 'col1','col2' by the select statement to retrieve columns names the system throws the following error:
ORA-00936: missing expression
00936. 00000 - "missing expression"
*Cause:
*Action:
Error at Line: 39 Column: 40
CODE:
SELECT * FROM
(
SELECT table_name, column_name
FROM ALL_TAB_COLUMNS
WHERE
table_name = 'DIM_XYZ'
)
PIVOT
(
MIN(column_name)
FOR column_name IN (
--code below does not work when plugged in the statement above
SELECT DISTINCT
LISTAGG('''' || column_name || '''', ',')
WITHIN GROUP (ORDER BY column_name) AS temp_in_statement
FROM (SELECT DISTINCT column_name FROM all_tab_columns WHERE table_name = 'DIM_XYZ')
--code above does not work
)
)
ORDER BY table_name;
----------------
do you guys have any idea how to solve this problem?
You cannot directly add dynamic expressions as an input to Pivot table,
You can try something like this where we retrieve all the columns of the table in a variable via a PL/SQL Block and then pass it in a way to the expected by the Oracle Pivot Table Functionality.
SET serveroutput ON;
DECLARE
sqlquery VARCHAR(32767);
cols VARCHAR2(32767);
BEGIN
SELECT listagg('''' || column_name || '''', ',') within
GROUP(
ORDER BY column_name)
INTO cols
FROM
(SELECT DISTINCT column_name
FROM all_tab_columns
WHERE TABLE_NAME = 'TABLE_NAME')
;
sqlquery := '
SELECT * FROM
(
SELECT table_name, column_name
FROM ALL_TAB_COLUMNS
WHERE
table_name = ''TABLE_NAME''
)
PIVOT
(
MIN(column_name)
FOR column_name IN (
''||cols||''
)
)
ORDER BY table_name';
DBMS_OUTPUT.PUT_LINE(sqlquery);
EXECUTE IMMEDIATE sqlquery;
END;
/

how to update all tables with a particular column name

I am trying to update all tables starting with string like 'agg%' and column_name ='%userid%'...
But i dont see any such examples online even though i was able to find option to select all tables with a particular column name and table name I need to do the same to update those tables something like this :
update TABLE_NAME set COLUMN_NAME='rajeev' WHERE COLUMN_NAME LIKE '%userid%'
and TABLE_NAME LIKE 'agg%'
FROM INFORMATION_SCHEMA.COLUMNS;
Help would be appreciated.
Thanks.
To get the update query for your condition
select
'update '||c.table_name||' set '||c.COLUMN_NAME||' = ''rajeev'';'
as my_update_query
from
(select
table_name,COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where table_name LIKE 'agg%' and COLUMN_NAME LIKE '%userid%') c
To execute
do $$
declare
arow record;
begin
for arow in
select
'update '||c.table_name||' set '||c.COLUMN_NAME||' = ''rajeev'';'
as my_update_query
from
(select
table_name,COLUMN_NAME
from INFORMATION_SCHEMA.COLUMNS
where table_name LIKE 'agg%' and COLUMN_NAME LIKE '%userid%') c
loop
execute arow.my_update_query;
end loop;
end;
$$;

Dynamically select the columns to be used in a SELECT statement

I would love to be able to use the system tables (Oracle in this case) to drive which fields are used in a SELECT statement. Something like:
SELECT
(
select column_name
from all_tab_cols
where table_Name='CLARITY_SER'
AND OWNER='CLARITY'
AND data_type='DATE'
)
FROM CLARITY_SER
This syntax doesn't work, as the subquery returns multiple rows, instead of one row with multiple columns.
Is it possible to generate a SQL statement dynamically by querying the table schema information in order to select only certain columns?
** edit **
Do this without using a function or procedure, if possible.
You can do this:
declare
l_sql varchar2(32767);
rc sys_refcursor;
begin
l_sql := 'select ';
for r in
( select column_name
from all_tab_cols
where table_Name='CLARITY_SER'
AND OWNER='CLARITY'
AND data_type='DATE'
)
loop
l_sql := l_sql || r.column_name || ',';
end loop;
l_sql := rtrim(l_sql,',') || ' from clarity_ser';
open rc for l_sql;
...
end;
No, it's not possible to specify a column list dynamically in SQL. You'll need to use a procedural language to run the first query, use that to construct a second query, then run the second query.
You could use dynamic SQL. Create a function that takes the table name, owner, data type, executes the inner query and returns a comma-separated list of column names, or an array table if you prefer. Then construct the outer query and execute it with execute immediate.
CREATE FUNCTION get_column_list(
table_name IN varchar2,
owner_name IN varchar2,
data_type IN varchar2)
RETURN varchar2
IS
BEGIN
...... (get columns and return comma-separated list)
END;
/
If your function returns a comma-separated list you can inline it:
execute immediate 'select ' || get_column_list(table_name, owner_name, datatype) || ' from ' || table_name
Admittedly it's a long time since I played with oracle so I may be a bit off but I'm pretty sure this is quite doable.
In SQLPlus you could do this:
COLUMN cols NEW_VALUE cols
SELECT max( ltrim( sys_connect_by_path( column_name, ',' ), ',' ) ) cols
FROM
(
select rownum rn, column_name
from all_tab_cols
where table_Name='CLARITY_SER'
and OWNER='CLARITY'
AND data_type='DATE'
)
start with rn = 1 connect by rn = prior rn +1
;
select &cols from clarity.clarity_ser;