How to get comparison operator from string to where clause - sql

I have data in reference table like <55, >60 (etc) and in source the values will come 40, 70 (etc). So based on reference values I have to check condition.
Example ;
if the value reference table is <55
my condition in where clause would be 40<55
if it is >70
my condition in where clause would be
40>60
actaully I am checking multipule condition on different fileds on where where .. this is going to be one of condition with AND.
Can you suggest me the way to handle it .
Thanks in advance

SQL> column str format A10;
SQL> WITH ref_data
2 AS (SELECT '<55' VAL
3 FROM dual
4 UNION ALL
5 SELECT '>60' val
6 FROM dual),
7 source_data
8 AS (SELECT 40 VAL
9 FROM dual
10 UNION ALL
11 SELECT 70 VAL
12 FROM dual)
13 SELECT CASE
14 WHEN B.val < To_number(Regexp_substr(A.val, '[[:digit:]]+')) THEN B.val
15 ||'<'
16 ||
17 Regexp_substr(A.val, '[[:digit:]]+')
18 ELSE B.val
19 ||'>'
20 ||Regexp_substr(A.val, '[[:digit:]]+')
21 END str
22 FROM ref_data A,
23 source_data b;
STR
----------
40<55
70>55
40<60
70>60
SQL>

Related

How can I select a data from another column from rows that have been selected?

I tried my best to figure and google this out, but couldn't really find a solid answer to it.
The problem I'm facing is that
Table 1:
ID Value 1
1 a
2 b
3 c
Table 2:
ID Value 2
1 4a
3 5b
4 6c
and I'd basically have to select the value from Table 1 that doesn't exist on Table 2 (Thus, 'b')
I can select and identify the ID that I want by using minus function between the tables, but can't seem to figure out a way to call a query to instead call the data.
Use the MINUS as a subquery (i.e. an inline view) (lines #14 - 16):
Sample data:
SQL> with
2 table1(id, value1) as
3 (select 1, 'a' from dual union all
4 select 2, 'b' from dual union all
5 select 3, 'c' from dual
6 ),
7 table2 (id, value2) as
8 (select 1, '4a' from dual union all
9 select 3, '5b' from dual union all
10 select 4, '6c' from dual
11 )
Query begins here:
12 select a.*
13 from table1 a
14 where a.id in (select t1.id from table1 t1
15 minus
16 select t2.id from table2 t2
17 );
ID VALUE1
---------- ----------
2 b
SQL>
Alternatively, use not exists:
<snip>
12 select a.*
13 from table1 a
14 where not exists (select null
15 from table2 b
16 where b.id = a.id
17 );
ID VALUE1
---------- ----------
2 b
SQL>

input table 1 (5 6 7) (Five Six Seven) and table 2 (5 6 7 ). Both in brackets are columns with values.,I want to get the five for the 5 in table2

table 1
col1
col2
5
five
6
six
8
eight
table 2
5|6|5
6|5
8|8|5
Expected output
|five|six|five|
|six|five|
|eight|eight|five|
That "link" you're talking about is called a join.
As you put it, that would be as follows:
Sample data (you already have that and don't type it):
SQL> with
2 table_1 (col1, col2) as
3 (select 5, 'five' from dual union all
4 select 6, 'six' from dual union all
5 select 8, 'eight' from dual
6 ),
7 table_2 (col1) as
8 (select 5 from dual union all
9 select 6 from dual union all
10 select 8 from dual
11 )
12 --
Query begins here:
13 select b.col1
14 from table_1 a join table_2 b on a.col1 = b.col1
15 where a.col2 = '&par_col2';
Enter value for par_col2: five
COL1
----------
5
SQL> /
Enter value for par_col2: eight
COL1
----------
8
SQL>
Depending on a tool you use, where clause might use a bind variable instead of a substitution one (I used in SQL*Plus), i.e.
where a.col2 = :par_col2
On the other hand, what do you need table_2 for? Everything you need is contained in table_1, so query would then be just
<snip>
13 select a.col1
14 from table_1 a
15 where a.col2 = '&par_col2';
Enter value for par_col2: six
COL1
----------
6
SQL>

Comparing a column value with another column value + a Value not working (Better description in the body)

My apologies for the title, don't know a better one.
I have the following issue, i got a complex Oracle database which requires the query to go through some hoops. For this specific query i want to see if there are any records in which Column A is Smaller then the Column B plus 0.1.
The WHERE is as following:
(
COALESCE(TO_NUMBER(REGEXP_SUBSTR("Column1", '^\d+')), 0)
<
(COALESCE(TO_NUMBER(REGEXP_SUBSTR("Column2", '^\d+')), 0) + 0.1)
)
The problem being is that it ignores the values behind the dot. For example :
Column1 = 25.4
Column2 = 25.2
This one should not be shown seeing 25.4 is larger then 25.3
If i say + 0.0 it does work correctly only showing the values where Column1 is small then column2 by nature.
If i use + 1.0 it also does it correctly, if i do +1.2 it only shows those that it jsut reats it as if it were + 1.0
Any suggestions? i'm not that experienced with Oracle, this is the only database (i sadly) have to work with using it.
Sample:
ID Column1 column2
1 25.4 25.2
2 RA 16
3 22 23.1
4 21 22
5 -12.2 -12.15
6 RA 0
7 11.3792 11.3538
8 0 -.023
9 1.05 .95
Based on your sample data, see if something like this helps:
SQL> with test (id, col1, col2) as
2 (select 1, '25.4', '25.2' from dual union all
3 select 2, 'RA' , '16' from dual union all
4 select 3, '22' , '23.1' from dual union all
5 select 4, '21' , '22' from dual union all
6 select 5, '-12.2', '-12.15' from dual union all
7 select 6, 'RA' , '0' from dual union all
8 select 7, '11.3972', '11.3538' from dual union all
9 select 8, '0', '-0.023' from dual union all
10 select 9, '1.05', '.95' from dual
11 ),
12 subset as
13 (select *
14 from test
15 where regexp_like(col1, '^(-)?(\d+)?(\.\d+)?$')
16 and regexp_like(col2, '^(-)?(\d+)?(\.\d+)?$')
17 )
18 select *
19 from subset
20 where to_number(col1, '999999999.99999999', 'nls_numeric_characters = .,') <
21 to_number(col2, '999999999.99999999', 'nls_numeric_characters = .,') + 0.1;
ID COL1 COL2
---------- ------- -------
3 22 23.1
4 21 22
5 -12.2 -12.15
7 11.3972 11.3538
8 0 -0.023
SQL>
subset CTE checks whether columns contain numbers
if so, the final select converts strings to numbers using format mask along with NLS_NUMERIC_CHARACTERS (to distinguish thousands separators from decimal points)
If data in those columns differ from the example and cause problems, post such cases and we'll see what next.
This is a situation where you can use a case expression:
(case when not regexp_like(column1, '^[0-9]+[.]?[0-9]*$')
then null
when not regexp_like(column2, '^[0-9]+[.]?[0-9]*$')
then null
where to_number(column1) < to_number(column1)
then 1
end) = 1
I'm not usually a fan of case expressions in conditional expressions. However, type conversion issues are a situation where they are useful.

Oracle SQL running total on change of field (SUM on column only when field changes)

I have a question in regards to how to SUM on a column only when a field is changing.
Take for example the table below:
Note that Column A and Column B are different tables. I.e. A was selected from Table X and B was selected from Table Y
SELECT X.A, Y.B
FROM X
INNER JOIN Y ON X.DATE = Y.DATE AND X.VAL1 =
Y.VAL1 AND X.VAL2 = Y.VAL2
A B
123 5
123 5
456 10
789 15
789 15
I need to sum column B on change of field on column A:
I.e. the query should return 5 + 10 + 15 = 30 (5 the first time because value in column A is 123, 10 the second time because column A changed from 123 to 456 - note that the second row was skipped because column A still contains value 123 - hence the change of field logic and so on).
I can't do a simple SUM(B) because that would return 50. I also cannot do SUM(B) OVER (PARTITION BY A) because that would do a running total by group, not by change of field.
My output needs to look like this:
A B X
123 5 5
123 5 5
456 10 15
789 15 30
789 15 30
I am trying to do this within a simple query. Is there a particular function I can use to do this?
For the simple data set provided, the following should work. You will, of course, want to review the ORDER BY clauses for correctness in your exact use case.
SELECT a
,b
,SUM(CASE WHEN a = prev_a THEN 0 ELSE b END) OVER (ORDER BY a RANGE UNBOUNDED PRECEDING) AS x
FROM (
SELECT a
,b
,LAG(a) OVER (ORDER BY a) AS prev_a
FROM {your_query}
)
This solution makes use of the LAG function, which returns the specified column from the previous result. Then the outer query's SUM gives the value only when the previous row didn't have the same value. And there is also the windowing clause involved in the SUM because you specified that you needed a running total.
Ta-daaa?
SQL> with test (a, b) as
2 (select 123, 5 from dual union all
3 select 123, 5 from dual union all
4 select 456, 10 from dual union all
5 select 789, 15 from dual union all
6 select 789, 15 from dual
7 ),
8 proba as(
9 select a, b,
10 case when a <> nvl(lag(a) over (order by a), 0) then 'Y' else 'N' end switch
11 from test
12 )
13 select a, b,
14 sum(decode(switch, 'Y', b, 0)) over (partition by null order by a) x
15 from proba
16 order by a;
A B X
---------- ---------- ----------
123 5 5
123 5 5
456 10 15
789 15 30
789 15 30
SQL>
you can also create a function and use it, see sample below,
create package test_pkg123
as
a number;
r_sum NUMBER;
function get_r_sum(p_a number, p_val NUMBER, rown NUMBER) return number;
end;
/
create or replace package body test_pkg123
as
function get_r_sum(p_a number, p_val NUMBER, rown NUMBER) return number
is
begin
if rown = 1 then
r_sum := p_val;
return r_sum;
end if;
if p_a != a then
r_sum := nvl(r_sum, 0) + nvl(p_val, 0);
end if;
a := p_a;
return r_sum;
end;
end;
/
with test (a, b) as
(select 123, 5 from dual union all
select 123, 5 from dual union all
select 456, 10 from dual union all
select 789, 15 from dual union all
select 789, 15 from dual union all
select 789, 15 from dual union all
select 123, 2 from dual
)
select a, b, test_pkg123.get_r_sum(a, b, rownum) r_sum
from test;
Output:
A B R_SUM
123 5 5
123 5 5
456 10 15
789 15 30
789 15 30
789 15 30
123 2 32
7 rows selected

where condition scenario in oracle

i have requirement in where condition
if my id is in 1 then it should check id 4,5,6,7 or it should check value which is in id
this id i will pass as parameter to query
select * from table_a where id
Help me in this
You can use the below
select * from individual ip
where (
( :p_prs_nat = 219 and ip.prs_nationality_id in (231,259,343) )
or (:p_prs_nat <> 219 and :p_prs_nat=ip.prs_nationality_id
))
where ip.prs_nationality_id =case when :p_prs_nat in( 219) then it shud check (231,259,343) else :p_prs_nat end how to achieve this functionality
You cannot directly use IN while returning the result in the THEN clause of CASE expression. However, you could first check the condition itself using AND operator and return TRUE whenever it matches.
For example,
SQL> WITH DATA AS
2 (
3 SELECT 1 ID, 'X' STR FROM DUAL UNION ALL
4 SELECT 2 ID, 'A' STR FROM DUAL UNION ALL
5 SELECT 3 ID ,'P' STR FROM DUAL UNION ALL
6 SELECT 4 ID ,'Q' STR FROM DUAL
7 )
8 SELECT *
9 FROM DATA
10 WHERE (
11 CASE
12 WHEN ID = 1
13 AND str IN ('A','Y','Z')
14 THEN 1
15 WHEN ID <> 1
16 THEN 1
17 END ) =1
18 /
ID S
---------- -
2 A
3 P
4 Q
SQL>
So, you did not get the row with ID = 1,since it did not match the condition AND str IN ('A','Y','Z').
If it would match, it will return those matching rows too:
SQL> WITH DATA AS
2 (
3 SELECT 1 ID, 'X' STR FROM DUAL UNION ALL
4 SELECT 2 ID, 'A' STR FROM DUAL UNION ALL
5 SELECT 3 ID ,'P' STR FROM DUAL UNION ALL
6 SELECT 4 ID ,'Q' STR FROM DUAL
7 )
8 SELECT *
9 FROM DATA
10 WHERE (
11 CASE
12 WHEN ID = 1
13 AND str IN ('X','Y','Z')
14 THEN 1
15 WHEN ID <> 1
16 THEN 1
17 END ) =1
18 /
ID S
---------- -
1 X
2 A
3 P
4 Q
SQL>