creating a dynamic where clause in oracle apex form - sql

I am creating a parameterized apex form where I take column name and its value from user via a select list.
When I use it in where clause like
select columnnames
from table
where :P592_column = :P592_value ;
It is not returning any output, but when I hardcode column name in place of :P592_column it is showing output.

You cannot use a bind variable as a dynamic column name. Instead, whitelist the columns in a CASE statement:
SELECT columnnames
FROM table
WHERE CASE UPPER( :P592_column )
WHEN 'COLUMN1' THEN column1
WHEN 'COLUMN2' THEN column2
WHEN 'COLUMN3' THEN column3
WHEN 'COLUMN4' THEN column4
END = :P592_value;
Or for multiple columns:
SELECT columnnames
FROM table
WHERE CASE UPPER( :P592_column )
WHEN 'COLUMN1' THEN column1
WHEN 'COLUMN2' THEN column2
WHEN 'COLUMN3' THEN column3
WHEN 'COLUMN4' THEN column4
END LIKE '%' || :P592_value || '%'
AND CASE UPPER( :P592_column1 )
WHEN 'COLUMN1' THEN column1
WHEN 'COLUMN2' THEN column2
WHEN 'COLUMN3' THEN column3
WHEN 'COLUMN4' THEN column4
END LIKE '%' || :P592_value1 || '%'
AND CASE UPPER( :P592_column2 )
WHEN 'COLUMN1' THEN column1
WHEN 'COLUMN2' THEN column2
WHEN 'COLUMN3' THEN column3
WHEN 'COLUMN4' THEN column4
END LIKE '%' || :P592_value2 || '%';

Related

What do the quotes mean in this SQL Server snippet? (SELECT '' column1, '' column 2)

I'd like to know the purpose of the two single quotes in front of each column. This is in a stored procedure. Thank you for your help!
INSERT INTO #temptable1
SELECT DISTINCT '' column1
,column2
,'' column3
,'' column4
FROM table1
WHERE column1 NOT LIKE 'string1%'
AND column2 <> 'string2'
AND column3 <> 'string3'
The expression '' is an empty string. So this is using an empty string instead of NULL for "missing" values.
I would write this code as:
SELECT DISTINCT '' as column1, column2, '' as column3, '' as column4
This might make it clearer. I always use as for column aliases -- so it is easier to spot missing commas (there should always be an as for a column alias).
More commonly, this would probably just use default values (which are usually NULL but could be ''):
INSERT INTO #temptable1 (column2)
SELECT DISTINCT column2
FROM table1
WHERE column1 NOT LIKE 'string1%'
AND column2 <> 'string2'
AND column3 <> 'string3';

Update composite column

I just want to fill column7 of my_table with values from other columns so the result for column7-value looks like that: 86|WWB|2014 or 86|WWB|- in case that column3 has value 0. Here is my SQL:
UPDATE public.my_table
SET column7 =
case when column1 IS NULL then '-' else column1 end
|| '|' ||
case when column2 IS NULL then '-' else column2 end
|| '|' ||
case when column3 = '0' then '-' else column3 end
error: invalid input syntax for integer: "_"
The problem ist the last case-row, because column3 is integer.
Column1 and column2 are bpchar, column3 ist int2.
Is there a way to solve this problem?
You are having type collisions. It is easy to convert in Postgres:
UPDATE public.my_table
SET column7 = (coalesce(column1::text, '-') || '|' ||
coalesce(column2::text, '-') || '|' ||
(case when column3 = 0 then '-' else column3::text end)
);
Using concat will make this a lot easier to read and it automatically converts everything to text. However the case statement needs to yield the same data type for all branches, so a cast to text is still needed for column3
UPDATE public.my_table
SET column7 = concat(
coalesce(column1, '-'), '|'
coalesce(column2, '-'), '|'
case when coalesce(column3,0) = 0 then '-' else column3::text end
);

SQL: How to check a value in column is equal to the sum of any combination of the other columns in a row

I came across a scenario where I have a table structure as such:
Column0 Column1 Column2 Column3 Column4 Column5
100 U V X Y Z
I need to find if:
100 = U, V, X, Y, or Z.
100 = X + Y + Z + V
100 = X + Y
100 = V + Z
etc.
Any suggestions of how I can achieve this?
Case statements will take forever to write. I do not write PL/SQL code but I am familiar with it somewhat.
Writing the Case statement isn't as hard as you're implying. I generated the following Case statement using a text editor in about 20 seconds, which should handle all situations in your example:
Select Case
When Column0 = Column1 Then 1
When Column0 = Column2 Then 1
When Column0 = Column3 Then 1
When Column0 = Column4 Then 1
When Column0 = Column5 Then 1
When Column0 = Column1 + Column2 Then 1
When Column0 = Column1 + Column3 Then 1
When Column0 = Column1 + Column4 Then 1
When Column0 = Column1 + Column5 Then 1
When Column0 = Column2 + Column3 Then 1
When Column0 = Column2 + Column4 Then 1
When Column0 = Column2 + Column5 Then 1
When Column0 = Column3 + Column4 Then 1
When Column0 = Column3 + Column5 Then 1
When Column0 = Column4 + Column5 Then 1
When Column0 = Column1 + Column2 + Column3 Then 1
When Column0 = Column1 + Column2 + Column4 Then 1
When Column0 = Column1 + Column2 + Column5 Then 1
When Column0 = Column1 + Column3 + Column4 Then 1
When Column0 = Column1 + Column3 + Column5 Then 1
When Column0 = Column1 + Column4 + Column5 Then 1
When Column0 = Column2 + Column3 + Column4 Then 1
When Column0 = Column2 + Column3 + Column5 Then 1
When Column0 = Column2 + Column4 + Column5 Then 1
When Column0 = Column3 + Column4 + Column5 Then 1
When Column0 = Column1 + Column2 + Column3 + Column4 Then 1
When Column0 = Column1 + Column2 + Column3 + Column5 Then 1
When Column0 = Column1 + Column3 + Column4 + Column5 Then 1
When Column0 = Column2 + Column3 + Column4 + Column5 Then 1
When Column0 = Column1 + Column2 + Column3 + Column4 + Column5 Then 1
Else 0
End As SumOfOtherColumns
From YourTable
Even if the answer has already been accepted, here is my alternative solution. It is, most probably way worse in terms of performance ( to be tested ) But I thought it was worth showing for the following reasons :
As you can see, with 5 columns it's already easy to miss some cases and there are only 31 cases to check. this goes to 63checks if you add a column, 127 for the next one ... you dont have to worry about that here because it will generate all the cases dynamically
The other interesting point is that, if you are interested in seeing the detail of each row and why it matched, it comes free with the query. you just have to select the subview
The last point is, I think it's academically interesting. The solution contains UNPIVOTing the data, self joining recursively, on the fly dynamic expression evaluation. Well of course, i'm not objective but hell that was fun to do :)
--Table and data to test the query
create table my_table ( column0 number, column1 number, column2 number,
column3 number, column4 number, column5 number );
INSERT INTO my_table values (100,20,20,10,40,10); -- must match on the sum of 5 columns
INSERT INTO my_table values (100,50,200,300,150,250); -- must not match
INSERT INTO my_table values (100,50,50,100,150,250); -- must match twice ( on col1+col2 and col3 )
-- If your table has a unique key, you can remove the datas_with_id and put
-- your table directly in the unpivoted_data subquery
with datas_with_id as ( select rowid as row_id, t.* from my_table t),
unpivoted_data as ( select row_id, column0 as sum_to_check, column_name, column_value
from datas_with_id
unpivot ( column_value for column_name in (column1,column2,column3,column4,column5))),
calculated_sum as ( select row_id, xmlquery(sys_connect_by_path(u.column_value,'+')||' = '|| sum_to_check
returning content).getStringVal() result
from unpivoted_data u connect by nocycle prior column_name>column_name
and prior row_id=row_id and level < 6)
select * from my_table where rowid in ( select row_id from calculated_sum where result = 'true' )
If you want to add another column, add it in the unpivot clause, add 1 to the level and you are good
and if you add sys_connect_by_path(u.column_name,'+')||' = '|| sum_to_check in the calculated_sum, you can see every formula that matched
Here I wrote some codes that you can use it dynamically
1-Firstly I create table and generate one row for it
create table my_table ( column0 number, column1 number, column2 number,
column3 number, column4 number, column5 number );
INSERT INTO my_table values (100,20,20,10,40,10);
2-create type as following lines
create or replace type Key_Value_Typ as object
(
column_name varchar2(100),
column_val varchar2(100)
)
3-you can see an example here
declare
lv_count number;
lv_row my_table%rowtype;
type my_list is table of Key_Value_Typ;
list1 my_list;
------------------------------------------------------------
-- function for control column condition
function check_fun(
lv_list my_list,
-- the function input is array of key value include column name and column value
-- you can implement your code here, for example as input parameter declare your own parameters
-- for example
-- lv_column0 my_table.column0%type;
lv_where varchar2
-- the condition that you want check it
) return number is
lv_str varchar2(200);
lv_count number;
begin
lv_str := lv_where;
for i in 1 .. lv_list.count Loop
lv_str := replace(lv_str,
lv_list(i).column_name,
lv_list(i).column_val);
ENd Loop;
execute immediate 'select count(*) from dual where ' || lv_str
into lv_count;
-- if the function return 1 result is true and o means result is false
return lv_count;
end check_fun;
------------------------------------------------------------
begin
-- fetch data from my_table and get one of them
select * into lv_row from my_table where column0 = 100;
-- create list of data include columns and values
list1 := my_list(Key_Value_Typ('column0', lv_row.column0),
Key_Value_Typ('column1', lv_row.column1),
Key_Value_Typ('column2', lv_row.column2),
Key_Value_Typ('column3', lv_row.column3),
Key_Value_Typ('column4', lv_row.column4),
Key_Value_Typ('column5', lv_row.column5));
lv_count := check_fun(list1, 'column0=column1+column2+column3+column4+column5');
dbms_output.put_line('result ()' || lv_count);
end;

Get values of 2 columns as single value separated with '|'

DECLARE #mockup TABLE(Column1 VARCHAR(1),Column2 VARCHAR(1));
INSERT INTO #mockup VALUES('1','2'),('-','2'),('1','2'),('-','-'),('2','-'),('1','2');
SELECT ISNULL(NULLIF(Column1 + '|','-|'),'')
+ISNULL(NULLIF(Column2,'-'),'')
FROM #mockup
Above query result is as below,
1|2
2
1|2
2|
1|2
I want the result as above only except row4, where 2| should be only as 2 .
'|' should not be there at before or end of the values.
Simply join both fields and use REPLACE to remove |- and -|. Condition in WHERE clause avoids records where both fields are -:
select replace(replace(Column1+'|'+Column2,'-|',''),'|-','') as Result
from mockup
where coalesce(nullif(Column1,'-'),nullif(Column2,'-')) is not null
Output:
Result
1|2
2
1|2
2
1|2
See result here.
Use Replace function
SELECT replace(replace(replace(Column1 + '|' + Column2,'-|',''),'|-',''),'-','')
FROM #mockup
or try using CASE statement
SELECT CASE
WHEN column1 LIKE '[0-9]' AND column2 LIKE '[0-9]' THEN column1 + '|' + column1
WHEN column1 LIKE '[0-9]' AND column2 NOT LIKE '[0-9]' THEN column1
ELSE column2
END
FROM #mockup
if you want to check the - instead of numbers then
SELECT CASE
WHEN column1 NOT LIKE '-' AND column2 NOT LIKE '-' THEN column1 + '|' + column1
WHEN column1 NOT LIKE '-' AND column2 LIKE '-' THEN column1
ELSE column2
END
FROM #mockup
I would do this as:
select stuff( ((case when column1 not like '-' then '|' + column1 else '' end) +
(case when column2 not like '-' then '|' + column2 else '' end)
), 1, 1, '');
This is the simplest way that I've found to implement concat_ws() in SQL Server. concat_ws() is a function available in other databases, where you would just do:
select concat_ws('|',
(case when column1 not like '-' then column1 end),
(case when column2 not like '-' then column2 end)
)

Update column if another column contains a string

I have a table that contains three columns.
column1 column2 column3
mytestdata test
myotherdata test
I want to insert 'somestring' into column3 if column1 contains the value in column2
The result would look like:
column1 column2 column3
mytestdata test 'somestring'
myotherdata test
SQL Server:
UPDATE myTable
SET column3 = 'somestring'
WHERE column1 LIKE '%' + column2 + '%'
SQL Server:
UPDATE theTable SET column3 = 'somestring'
WHERE CHARINDEX (column2, column1) > 0
You have several options, depending on the RDBMS.
For both MySQL and Oracle:
UPDATE yourTable
set column3 = 'somestring'
where INSTR(column2, column1) > 0
For SQL Server:
UPDATE yourTable
set column3 = 'somestring'
where CHARINDEX(column1, column2) > 0
You could do something like below
UPDATE tmp
SET
column3 = (CASE WHEN tmp.column1 like '%' + tmp.column2 + '%' THEN 'something' ELSE tmp.column3')
FROM
tablename tmp