join with exact match value otherwise join with default value - oracle

I have a table a
c1 c2 c3 c4 value
all all all all 5
all david all Y 6
all all cd all 7
and table b
c1 c2 c3 c4
a peter cd N
b david all Y
c all cd N
I want to have get the value from table a into table b, the desired results is like this:
c1 c2 c3 c4 Value
a david cd N 5
b david ab Y 6
c all cd N 7
That is use the default "all" value if there is no close match find.
Thanks a lot!

I see a couple of possibilities assuming you have some errors in your example result data. (C2 for value 5 and C3 for value 6 are suspect to me)
Use a CTE to union the results replace all with null and use aggregation to get max value
Use a Join on value and evaluate table a's value for each c column if it's not all use it, otherwise use B's value. (IF a and b are both all it doesn't matter which we use.) this may be problematic if both values are potentially different like if Value 6 had a Y in A, and a N in B. but no such example exits in your data so I'm trusting it doesn't happen. (or if it did, picking A's value is more appropriate if it's not all)
AS a cte: (Common Table expression)
WITH cte as (
SELECT replace(c1,'all',null)
, replace(c2,'all',null)
, replace(c3,'all',null)
, replace(c4,'all',null)
, value
FROM A
UNION ALL
SELECT replace(c1,'all',null)
, replace(c2,'all',null)
, replace(c3,'all',null)
, replace(c4,'all',null)
, value
FROM b)
/* We have to eval the max as if it's null we need to replace it with all
Might be able to avoid the replacing all provided all values of c1-c4 are
greater than all... replacing just seemed safer. at a hit to performance.*/
SELECT coalesce(max(c1),'all') as c1
,coalesce(max(c2),'all') as c2
,coalesce(max(c3),'all') as c3
,coalesce(max(c4),'all') as c4
,value
FROM cte
GROUP BY value
Using a join (simpler from a maintenance and perhaps performance standpoint)
SELECT case when A.C1 <> 'all' then A.C1 else B.c1 end as C1,
case when A.C2 <> 'all' then A.C2 else B.c2 end as C2,
case when A.C3 <> 'all' then A.C3 else B.c3 end as C3,
case when A.C4 <> 'all' then A.C4 else B.C4 end as C4,
A.value --A.val = b.val so it doesn't matter which se use.
FROM A
INNER JOIN B
on A.value = B.Value
Depending on existing indexes and data volume the first approach might be better than the second.

Related

In Clickhouse, how can I obtain the rows, in which all columns are non-null / not empty?

Consider the following table:
A | B | C
+++++++++++++++++++
15 | | 25
10 | 20 | 30
which, for the sake of simplicity, contains only two rows. Now, when I issue this query
SELECT A, B, C FROM whatever
I would like to obtain only the second row, i. e. only these rows, where every value is non-null / not empty. Instead, I get both rows.
Is there a better way than doing the following? :
SELECT A, B, C FROM whatever
WHERE A != '' AND B != '' AND C !=''
You can use function empty to mark empty or non-empty rows as 1 if the row is empty and 0 if there is any data in it.
So your code will look like this
SELECT A
, B
, C
, empty(A) as empty_A
, empty(B) as empty_B
, empty(A) as empty_C
FROM whatever
WHERE empty_A = 0 AND empty_B = 0 AND C empty_C = 0
Thus, if there is at least one empty in columns A / B / C, then these rows will not fall into selection
In addition to the previous answer, just to be more straight, you can use the following code that combine the empty function with the trim one to spot also columns containing one or more white spaces.
SELECT col_1, col_2, col_3
FROM my_table
WHERE empty(trim(col_2)) = 0

comparing values from two oracle table columns and getting starting value

I Have oracle table with data as shown below.
column1 column2
A1 B1
B1 C1
C1 D1
I need to get A1 value from D1. I have to implemet this in View. Need to traverse using as D1 as input and get C1 and get B1 from C1 and finally A1 using B1
Please help.
Not sure what kind of view you are looking to create; if you are thinking of passing 'A1' as an input to the view, there is no such thing in Oracle as far as I know, you would need to use a cursor for that.
The following SELECT statement can be used as an inline view (a subquery) and you can make the 'D1' value at the end of it into a bind variable if needed.
select column1
from test_data
where connect_by_isleaf = 1
connect by column2 = prior column1
start with column2 = 'D1'
;

substr function for substract the column value basis of another column in oracle

How to use substr function in oracle to substract the column value
based on another column vale in same table.
For example:suppose table abc having some column value like a=01-CEDAPR while B=AB_52MM_01-CEDAPR
Now i want to populate the column c on the basis of value AB_52MM. can any one suggest me
what is right way to achieve this .
This should be relatively straightforward. All you want to do is replace the value of a, if found in b, with nothing. Right?
WITH abc AS (
SELECT '01-CEDAPR' AS a, 'AB_52MM_01-CEDAPR' AS b
FROM dual
)
SELECT a, b, REPLACE(b, a)
FROM abc
See SQL Fiddle Demo here.
If you need to replace the _ preceding the value of a, then you might want to use REGEXP_REPLACE() (in case the _ may or may not exist):
WITH abc AS (
SELECT '01-CEDAPR' AS a, 'AB_52MM_01-CEDAPR' AS b
FROM dual
)
SELECT a, b, REGEXP_REPLACE(b, '_?' || a || '$')
FROM abc
The $ sign ensures that the value of a is anchored to the end; the ? makes _ optional.
SQL Fiddle Demo here.
Here's a couple of solutions that may or may not help you, based on the sketchy information you have provided. If they don't, then you will need to edit your question to provide more a more detailed explanation of what you're after!
with sd as (select '01-CEDAPR' a, 'AB_52MM_01-CEDAPR' b from dual) -- assumed O1 in column b was a typo
select a,
b,
regexp_replace(b, '_'||a),
substr(b, 1, instr(b, '_', -1) -1)
from sd;

is possible : cast char to varchar while join table in oracle

Can I cast B1 char(2) which joins on A1 varchar2(2) :
SELECT * FROM A
LEFT JOIN B
ON CAST(B.B1 AS VARCHAR2(2)) = A.A1
It results to no errors, but there no data displayed.
Is the above query possible?
You can cast it, but it isn't doing that you think, or seem to be relying on. Assuming you have a one-character value in the field you're joining on, you don't get a match, with or without the cast:
create table a (a1 varchar2(2));
create table b (b1 char(2));
insert into a values ('X');
insert into b values ('X');
select * from a left join b on b.b1 = a.a1;
A1 B1
-- --
X
select * from a left join b on cast(b.b1 as varchar2(2)) = a.a1;
A1 B1
-- --
X
The cast is chaging the data type, but not the data; it is still blank-padded. The only difference is that it's done explicitly in the value, rather implicitly as you'd see with a char. You can verify that the value is the same with the dump() function:
select dump(b.b1) dump_char,
dump(cast(b.b1 as varchar2(2))) dump_varchar2
from b;
DUMP_CHAR DUMP_VARCHAR2
-------------------- --------------------
Typ=96 Len=2: 88,32 Typ=1 Len=2: 88,32
So the type has changed, from 96 (char) to 1 (varchar2), but the value is the same. Compare that with your value in table A and you'll see they are not the same:
select dump(a.a1) dump_varchar2 from a;
DUMP_VARCHAR2
--------------------
Typ=1 Len=1: 88
Your cast B value still has the trailing space, the A value does not, therefore they don't match. You can remove that trailing space for comparison with trim() or rtrim():
select * from a left join b on rtrim(b.b1) = a.a1;
A1 B1
-- --
X X
There is an implicit conversion from char to varchar2 within the rtrim() call, so you could still cast that explicitly for clarity.
Note that this assumes you never have a trailing space in A. It may be safer to cast the other way:
select * from a left join b on b.b1 = cast(a.a1 as char(2));
A1 B1
-- --
X X
... but which side you cast/trim will also affect which indexes can be used.
this worked for me:
SELECT * FROM A
LEFT JOIN B
ON TRIM(B.B1) = A.A1
i prefer this syntax to the cast for purely aesthetic reasons, although presumably others exist

Oracle sql statement, how to created good statement for current case?

I have a table which looks like this
id
name
problem
1
A1
Good
2
A2
Bad
1
A1
Good
2
A2
Good
What I expect to recive from this table, for unique id, and name, we can have different problem,
E.g.:
If A1 = Good for all cases, I need to return 1 A1 Good,
If A2 = Good and also A2 = Bad, I need to return 2 A2 Bad
Expected result should looks like
id
name
problem
1
A1
Good
2
A2
Bad
Something like this (although I'm not 100% sure I understand the problem)
select id,
name,
case
when total_count = good_count then 'Good'
else 'Bad'
end as problem
from (
select id,
name,
count(*) as total_count,
case (when problem = 'Good' then 1 end) as good_count
from the_table
group by id, name
)
This counts the total items for each id/name combination and counts the number of "Good" items. If the total count equals the "good" count that Good will be displayed otherwise 'Bad'

Resources