Apex select list vales as column names - sql

I have a select list (:P31_LIST) with static values (column1, column2, column3) and a table with the same columns names.
How to select and insert data into a column of the table selected by the user, using the select list? How can I use the value of the select list as column table name ? I tried this query but no data was inserted or selected:
-- Select
select column1, :P31_LIST,
---Tried also this
case when :P31_LIST= 'column1' then (select column1 from my_table) END as test,
from my_table
-- Insert
Insert into my_table(:P31_LIST, column2)
SELECT A,
B
FROM source_table
my_table looks like this:
column1 | column2 | column3
1 | 2 | 3

For a SELECT you can either, use a CASE expression and whitelist the column names:
select column1,
CASE :P31_LIST
WHEN 'column1' THEN column1
WHEN 'column2' THEN column2
WHEN 'column3' THEN column3
ELSE NULL
END AS value
from my_table
Or, using dynamic SQL in a PL/SQL block:
DECLARE
v_sql CLOB := 'select column1, ' || :P31_LIST || ' AS value from my_table';
BEGIN
FOR r IN v_sql LOOP
DBMS_OUTPUT.PUT_LINE( r.column1 || ', ' || r.value);
END LOOP;
END;
/
For an INSERT, use PL/SQL:
BEGIN
EXECUTE IMMEDIATE 'INSERT INTO my_table(' || :P31_LIST || ', column2) SELECT A, B FROM source_table';
END;
/
or whitelist the columns:
BEGIN
IF :P31_LIST = 'column1' THEN
INSERT INTO my_table(column1, column2) SELECT A, B FROM source_table;
ELSIF :P31_LIST = 'column3' THEN
INSERT INTO my_table(column3, column2) SELECT A, B FROM source_table;
END IF;
END;
/

Related

Need help on writing sql query with dynamic columns

I have to write a query which does below. I tried but couldn't write. Please help me.
I have table which returns below result set.
select *
from table1; --(rowid and ColumnName are columns of the table)
Output:
rowid ColumnName
------------------------------
1 Segment1
2 Segment2
I have another table which has below structure : (Segment1 and Segment2 are columns here)
select *
from table2;
Output:
appId Segment1 Segment2 Segment3
---------------------------------------------
a1 fld1 fld2 per
a2 cmp1 hcd4 klp
I need to write a query, which reads the "ColumnName" values from first table and retrieves column values in the second table.
That means, from the table1, I will know what are the available columns I the table2 and from table2, I will know what is the data stored against those columns.
Please let me know if I am not clear.
This query is in Oracle SQL
As mentioned in the comment you need a PLSQL block with dynamic sql. See below an example:
Tables:
create table table1 (row_id number,
ColumnName varchar2(100))
create table table2 (appId number,
Segment1 varchar2(100),
Segment2 varchar2(100),
Segment3 varchar2(100));
Insert all
into TABLE1 (ROW_ID, COLUMNNAME) Values (1, 'Segment1')
into TABLE1 (ROW_ID, COLUMNNAME) Values (2, 'Segment2')
into TABLE2 (APPID, SEGMENT1, SEGMENT2, SEGMENT3) Values (1, 'RRR', 'KKK', 'MMM')
into TABLE2 (APPID, SEGMENT1, SEGMENT2, SEGMENT3) Values (2, 'ZZZ', 'PPP', 'QQQ')
into TABLE2 (APPID, SEGMENT1, SEGMENT2, SEGMENT3) Values (3, 'LLL', 'NNN', 'DDD')
select * from dual;
Code:
DECLARE
var VARCHAR2 (1000);
v_sql VARCHAR2 (2000);
TYPE x_var IS TABLE OF VARCHAR2(1000);
z_var x_var;
num number:=0;
BEGIN
FOR rec IN ( SELECT DISTINCT columnname
FROM table1
ORDER BY 1)
LOOP
num := num +1;
if num = 1 then
var:= rec.columnname;
else
var := var || ' || '' , ''||' || rec.columnname;
end if;
END LOOP;
var := RTRIM (LTRIM (var, ','), ',');
v_sql := 'select '|| var ||' from table2';
EXECUTE IMMEDIATE v_sql BULK COLLECT INTO z_var;
FOR i IN 1 .. z_var.COUNT
LOOP
DBMS_OUTPUT.put_line (z_var(i));
END LOOP;
END;
Output:
SQL> /
RRR , KKK
ZZZ , PPP
LLL , NNN
Dynamic columns in a SQL statement are almost always a bad idea. There's usually a way to avoid these kind of problems and build a simpler solution.
But if this is one of those rare times when you really need to run dynamic SQL in SQL then you'll need to install and run something like my open source project Method4.
For example:
create table table1 as
select 1 id, 'Segment1' columnName from dual union all
select 2 id, 'Segment2' columnName from dual;
create table table2 as
select 'a1' appId, 'fld1' Segment1, 'fld2' Segment2, 'per' Segment3 from dual union all
select 'a2' appId, 'cmp1' Segment1, 'hcd4' Segment2, 'klp' Segment3 from dual;
select * from table(method4.dynamic_query(
q'[
select
'select appID, '
||listagg(columnName, ',') within group (order by id)
||' from table2'
sql_statement
from table1
]'
));
APPID SEGMENT1 SEGMENT2
----- -------- --------
a1 fld1 fld2
a2 cmp1 hcd4
There are a lot of downsides to running this way. The code is complicated, slow, and has some odd behavior. For an explanation of how this works, see this article
by Adrian Billington.
Will the below PL SQL block help your requirement.
BEGIN
FOR iter IN (
SELECT column_name
FROM all_tab_columns
WHERE upper(table_name) = 'table1'
AND UPPER(column_name) LIKE 'SEGMENT%'
)
LOOP
SELECT iter.column_name INTO temp_table FROM table1
dbms_output.put_line(temp_table.column_name);
END LOOP;
END;
/
Say you have tables like the following:
SQL> select * from someTable;
COLUMN1 COLUMN2 COLUMN3
---------- ---------- ----------
1 2 3
2 4 6
3 6 9
SQL> select * from tableOfColumns;
COLUMNN
-------
column1
column3
You may need something like the following:
SQL> declare
2 type tListOfResults is table of varchar2(1000);
3 vSQL varchar2(1000);
4 vResult tListOfResults ;
5 begin
6 select 'select ' || listagg (columnName, ' || '', '' || ') within group (order by columnName) || ' from someTable'
7 into vSQL
8 from tableOfColumns;
9 --
10 execute immediate vSQL bulk collect into vResult;
11 if vResult.count() > 0 then
12 for i in vResult.first .. vResult.last loop
13 dbms_output.put_line(vResult(i));
14 end loop;
15 end if;
16 end;
17 /
1, 3
2, 6
3, 9
PL/SQL procedure successfully completed.

Vertica. Count of Null and Not-Null of all columns of a Table

How can we get null and non-null counts of all columns of a Table in Vertica? Table can have n number of columns and for each column we need to get count of nulls and non-nulls values of that table.
For Example.
Below Table has two columns
column1 Column2
1 abc
pqr
3
asd
5
If its a specific column then we can check like
SELECT COUNT(*) FROM table where column1 is null;
SELECT COUNT(*) FROM table where column1 is not null;
Same query for column2
I checked system tables like projection_storage and others but I cant figure out a generic query which gives details by hard coding only TABLE NAME in the query.
Hello #user2452689: Here is a dynamically generated VSQL statement which meets your requirement of counting nulls & not nulls in N columns. Notice that this writes a temporary SQL file out to your working directory, and then execute it via the \i command. You only need to change the first two variables per table. Hope this helps - good luck! :-D
--CHANGE SCHEMA AND TABLE PARAMETERS ONLY:
\set table_schema '\'public\''
\set table_name '\'dim_promotion\''
---------
\o temp_sql_file
\pset tuples_only
select e'select \'' || :table_schema || e'\.' || :table_name || e'\' as table_source' as txt
union all
select * from (
select
', sum(case when ' || column_name || ' is not null then 1 else 0 end) as ' || column_name || '_NOT_NULL
, sum(case when ' || column_name || ' is null then 1 else 0 end) as ' || column_name || '_NULL' as txt
from columns
where table_schema = :table_schema
and table_name = :table_name
order by ordinal_position
) x
union all
select ' from ' || :table_schema || e'.' || :table_name || ';' as txt ;
\o
\pset tuples_only
\i temp_sql_file
You can use:
select count(*) as cnt,
count(column1) as cnt_column1,
count(column2) as cnt_column2
from t;
count() with a column name or expression counts the number of non-NULL values in the column/expression.
(Obviously, the number of NULL values is cnt - cnt_columnX.)
select column1_not_null
,column2_not_null
,column3_not_null
,cnt - column1_not_null as column1_null
,cnt - column2_not_null as column2_null
,cnt - column3_not_null as column3_null
from (select count(*) as cnt
,count (column1) as column1_not_null
,count (column2) as column2_not_null
,count (column3) as column3_not_null
from mytable
) t

How to select all columns while trimming the result of one of them?

I have a table
This query will select all columns as they are.
select * from t1
But I need to trim one of those columns.
Can I do it this way?
select *
case
when column4 is not null
then substr(column4, - 5)
from table
Or do I need
select *
case
when column4 is not null
then column4 = substr(column4, - 5)
from table
The result should have all columns exept column4 unchanged.
There's no operator for "all columns except something", unfortunately. You'd have to specify all of them:
SELECT column1, column2, column3, SUBSTRING(column4, LENGTH(column4) - 5), etc
FROM mytable
syntax should be like this:
select column1,
column2,
column3,
case
when column4 is not null
then substring(column4, length(column4) - 5)
end column4 ,
column5
from table;
It depends a bit on what you want to accomplish. This works:
select substr(column4, 0, 5), t1.* from sometable t1;
However, it returns column4 twice. Once with 5 characters (use length as in the other answers if you want to discard the last 5 rather than using a fixed length, not clear what your goal is) and once with all characters.
You could also generate the SQL with PL/SQL using user_tab_columns. If you just want to save yourself some typing something like this might work:
declare
v_sql varchar2(1024) := null;
begin
for rec in (select column_name, table_name from user_tab_columns
where table_name = 'TEST1') loop
if v_sql is null then
v_sql := 'select ';
else
v_sql := v_sql || ',';
end if;
if rec.column_name = 'C2' then
v_sql := v_sql || ' substr(' || rec.table_name || '.c2, 0, 5)';
else
v_sql := v_sql || rec.table_name || '.' || rec.column_name;
end if;
end loop;
v_sql := v_sql || ' from test1';
dbms_output.put_line(v_sql);
end;
/
No points for code style, but it works and prints the SQL. Add more special cases if you need to truncate multiple columns and add the other tables as needed.

Getting a count by value of all columns in a table using Oracle SQL

For various reasons the organisation I work for has data stored on both Oracle and MS SQL server databases. We are moving some static historical data over and I have to check that the data has been moved properly.
The Query below checks the data in SQL server and produces a table listing counts of all the values in each column of the table.
Due to formatting differences in Oracle I will need to group by two other columns Year and Iteration_count . I have not been able to get a loop through of all columns in a table working in Oracle as my experience is pretty much limited to SQL Server
DECLARE #SQL NVARCHAR(MAX) = ''
SELECT #SQL = STUFF((SELECT ' UNION SELECT ''' + name
+ ''' AS [Column], '
+ 'CAST(' + QUOTENAME(Name)
+ ' AS NVARCHAR(MAX)) AS [ColumnValue], COUNT(*) AS [Count] FROM '
+'dbo.HES_APC_ACP_9798'
+' where (NUMACP IS NOT NULL AND NOT (NUMACP = 0) ) '
+' GROUP BY ' + QUOTENAME(Name)
--+'Order By [Column],[ColumnValue]'
FROM sys.columns
WHERE object_id = Object_id('dbo.HES_APC_ACP_9798' )
FOR XML PATH ('')), 1, 7, '');
EXECUTE sp_executesql #SQL;
This loop on user_tab_columns should help:
declare
v_table varchar2(30) := 'TEST';
v_sql varchar2(32767);
begin
for r in (select column_name name from user_tab_cols
where table_name=v_table order by column_id)
loop
v_sql := v_sql||' union all select '''||r.name||''' col_name, to_char('
||r.name||') col_value, count(1) cnt from '||v_table
||' group by '||r.name||chr(13);
end loop;
v_sql := ltrim(v_sql, ' union all ');
dbms_output.put_line(v_sql);
end;
Test table:
create table test (col1 varchar2(10), col2 number(5), col3 date);
insert into test values ('ABC', 1, null);
insert into test values ('DEF', 1, date '2015-06-18');
Executing first PLSQL block outputs:
select 'COL1' col_name, to_char(COL1) col_value, count(1) cnt from TEST group by COL1
union all select 'COL2' col_name, to_char(COL2) col_value, count(1) cnt from TEST group by COL2
union all select 'COL3' col_name, to_char(COL3) col_value, count(1) cnt from TEST group by COL3
Output of this query:
COL_NAME COL_VALUE CNT
-------- ------------ ----------
COL1 DEF 1
COL1 ABC 1
COL2 1 2
COL3 1
COL3 15/06/18 1
Use all_tab_cols and add filter for owner if you read data from other schema. You can also run generated query using execute immediate statement.

Customize SQL query

I have requirement where in I am creating a table dynamically(number of columns may change based on input parameter to my procedure through which I am creating this table) with data in the table like below.
PK col1 col2 col3
A null 1-2 3-4
B null null 4-5
C null 5-6 null
Now the requirement is I want to extract only the columns where at least there should be 1 record without null and spool the whole data into a file. My output should be like below (col1 exlluded from output as it has all nulls).
PK col2 col3
A 1-2 3-4
B null 4-5
C 5-6 null
Can anybody provide any hints to achieve this. Thanks in advance.
This won't be very efficient I suspect, but you can use COUNT() to determine if there are any only NULLS in a column because COUNT(column_here) will only add 1 for each non-null value. Hence if the count is zero that column is only NULLs.
This can then be combined into a query to generate a valid select statement and then that executed immediate (being careful of course to avoid sql injection).
Anyway, here's an example:
select
'select '
|| substr((
select
case when count(COL1) > 0 then ',col1' else '' end
|| case when count(COL2) > 0 then ',col2' else '' end
|| case when count(COL3) > 0 then ',col3' else '' end
from a_table
),2,8000)
|| ' from '
|| ' a_table'
as sql_string
from dual
;
see this sqlfiddle
result by the above is:
| SQL_STRING |
|--------------------------------|
| select col2,col3 from a_table |
Here is a try. First, create a function to generate your query, returning a REF CURSOR:
create or replace function select_non_nulls() return sys_refcursor as
myQuery varchar2(500);
myCur sys_refcursor;
begin
select 'select ' || listagg(col, ', ') within group (order by col) || ' from test'
into myQuery
from
(
select case when max(col1) is null then null else 'col1' end col from test
union all
select case when max(col2) is null then null else 'col2' end col from test
union all
select case when max(col3) is null then null else 'col3' end col from test
)
;
open myCur for myQuery;
return myCur;
end;
/
Then use it in SQL*Plus:
SQL> var rc refcursor
SQL> exec :rc := select_non_nulls;
SQL> print rc;
I used num_nulls from all_tab_cols and achieved result as per my requirement. Thank you.