Merging exists and not exists into one query - oracle magic - oracle

In a WHERE part of query we have
SELECT * FROM SomeTable st
WHERE
NOT EXISTS
(SELECT 1 FROM Tab t1 WHERE t1.A = st.A OR t1.B = st.A)
OR EXISTS
(SELECT 1 FROM Tab t2 WHERE (t2.A = st.A OR t2.B = st.A) AND t2.C IS NULL)
Seems like a good candidate for merging...
But I'm staring on that for an hour without any idea.
Would you have some thoughts?
Thanks,

SELECT distinct st.*
FROM SomeTable st
left outer join Tab t
on st.a in (t.a,t.b)
WHERE t.c is null
Sometimes the simplest answer is to use a join rather than an exists.

Try:
NOT EXISTS (SELECT 1 FROM Tab WHERE (Tab.A = #Id OR Tab.B = #ID)
AND (Tab.C is null OR Tab.C != #Var))

I think I've got it
SELECT * FROM SomeTable st
WHERE
0 = (SELECT SUM (NVL(t1.C,0) FROM Tab t1 WHERE t1.A = st.A OR t1.B = st.A)
What do you think?
Of course that will work only for case where 'C' is expected to be NULL.
If we are expecting some value, I think that the check
#SomeValue IN (SELECT t1.C FROM Tab t1 WHERE t1.A = st.A OR t1.B = st.A)
Will do?

It looks as though you're trying to return all SomeTable values where there's no corresponding value on Tab where C is not null - in which case, the following should work:
SELECT * FROM SomeTable st
WHERE NOT EXISTS
(SELECT 1 FROM Tab t1 WHERE (t1.A = st.A OR t1.B = st.A) AND t2.C IS NOT NULL)
However, that's not exactly what your existing query does - in your query, if there are two corresponding records on Tab, where one record has a non-null value for C and the other is null, your query will return a corresponding row, but my query won't.

Related

how to select specific columns from three different tables in Oracle SQL

I am trying to select values from three different tables.
When I select all columns it works well, but if I select specific column, the SQL Error [42000]: JDBC-8027:Column name is ambiguous. appear.
this is the query that selected all that works well
SELECT
*
FROM (SELECT x.*, B.*,C.* , COUNT(*) OVER (PARTITION BY x.POLICY_NO) policy_no_count
FROM YIP.YOUTH_POLICY x
LEFT JOIN
YIP.YOUTH_POLICY_AREA B
ON x.POLICY_NO = B.POLICY_NO
LEFT JOIN
YIP.YOUTH_SMALL_CATEGORY C
ON B.SMALL_CATEGORY_SID = C.SMALL_CATEGORY_SID
ORDER BY x.POLICY_NO);
and this is the error query
SELECT DISTINCT
x.POLICY_NO,
x.POLICY_TITLE,
policy_no_count ,
B.SMALL_CATEGORY_SID,
C.SMALL_CATEGORY_TITLE
FROM (SELECT x.*, B.*,C.* , COUNT(*) OVER (PARTITION BY x.POLICY_NO) policy_no_count
FROM YIP.YOUTH_POLICY x
LEFT JOIN
YIP.YOUTH_POLICY_AREA B
ON x.POLICY_NO = B.POLICY_NO
LEFT JOIN
YIP.YOUTH_SMALL_CATEGORY C
ON B.SMALL_CATEGORY_SID = C.SMALL_CATEGORY_SID
ORDER BY x.POLICY_NO);
I am trying to select if A.POLICY_NO values duplicate rows more than 18, want to change C.SMALL_CATEGORY_TITLE values to "ZZ" and also want to cahge B.SMALL_CATEGORY_SID values to null.
that is why make 2 select in query like this
SELECT DISTINCT
x.POLICY_NO,
CASE WHEN (policy_no_count > 17) THEN 'ZZ' ELSE C.SMALL_CATEGORY_TITLE END AS C.SMALL_CATEGORY_TITLE,
CASE WHEN (policy_no_count > 17) THEN NULL ELSE B.SMALL_CATEGORY_SID END AS B.SMALL_CATEGORY_SID,
x.POLICY_TITLE
FROM (SELECT x.*, B.*,C.* , COUNT(*) OVER (PARTITION BY x.POLICY_NO) policy_no_count
FROM YIP.YOUTH_POLICY x
LEFT JOIN
YIP.YOUTH_POLICY_AREA B
ON x.POLICY_NO = B.POLICY_NO
LEFT JOIN
YIP.YOUTH_SMALL_CATEGORY C
ON B.SMALL_CATEGORY_SID = C.SMALL_CATEGORY_SID
ORDER BY x.POLICY_NO);
If i use that query, I got SQL Error [42000]: JDBC-8006:Missing FROM keyword. ¶at line 3, column 80 of null error..
I know I should solve it step by step. Is there any way to select specific columns?
That's most probably because of SELECT x.*, B.*,C.* - avoid asterisks - explicitly name all columns you need, and then pay attention to possible duplicate column names; if you have them, use column aliases.
For example, if that select (which is in a subquery) evaluates to
select x.id, x.name, b.id, b.name
then outer query doesn't know which id you want as two columns are named id (and also two names), so you'd have to
select x.id as x_id,
x.name as x_name,
b.id as b_id,
b.name as b_name
from ...
and - in outer query - select not just id, but e.g. x_id.

Check and save data to update

I have a question, I need, at the same time that I check, I need to save the value of a query to perform an update. How is it possible to do this? Someone help me?
update table_one tone
set tone.name = (name)
where (select tthree.name as name
from table_two ttwo
where ttwo.name='sfsdf'
union
select tthree.name as name
from table_three tthree
where tthree.name='sfsdf') is not null;
I'm not sure what you meant by saying that you want to "save" value of a query (save how? Where?) at the same time that you "check" (how? Where?). True, you posted some code which suggests that tone.name should get value of (name), but - what exactly is that (name)?
Anyway, this is what I think you might need, so - have a look & give it a try.
update table_one t1 set
t1.name = (select max(x.name)
from (select t2.name from table_two t2 where t2.name = 'sfsdf'
union
select t3.name from table_three t3 where t3.name = 'sfsdf'
) x
)
where exists (select null
from (select t2.name from table_two t2 where t2.name = 'sfsdf'
union
select t3.name from table_three t3 where t3.name = 'sfsdf'
)
);
If that's not "it", please, edit the question and post some sample data that illustrate the problem and explain which result you expect and why.

Oracle: Select two different rows from one table and select value from another table if any of the entry does not exist

These are the two tables. I want to select created time of TABLE1 for type = 'PENDINGTIMESTAMP' and type = 'DISTRIBUTEDTIMESTAMP' for TABLE2ID.
TABLE1
+------+--------+--------------------+-------------------+
|ID |TABLE2ID|TYPE |CREATED |
+------+--------+--------------------+-------------------+
|156174|849118 |PENDINGTIMESTAMP |2016-09-09 03:33:11|
|156175|849118 |DISTRIBUTEDTIMESTAMP|2016-09-09 03:33:11|
|156176|849118 |PROCESSTIME |2016-09-09 03:33:11|
|156177|849119 |DISTRIBUTEDTIMESTAMP|2016-09-09 03:33:11|
|156178|849119 |PROCESSTIME |2016-09-09 03:33:11|
+------+--------+--------------------+-------------------+
TABLE2
+------+-------------------+
|ID |CREATED |
+------+-------------------+
|849118|2016-09-09 05:00:00|
|849119|2016-09-09 06:00:00|
+------+-------------------+
If any of the entry not exist in TABLE1 for TABLE2ID then i want select created time of TABLE2.CREATED where TABLE2.ID
Final Result would be
+--------+-------------------+-------------------+
|TABLE2ID|TIME1 |TIME2 |
+--------+-------------------+-------------------+
|849118 |2016-09-09 03:33:11|2016-09-09 03:33:01|
|849119 |2016-09-09 06:00:00|2016-09-09 03:33:01|
+--------+-------------------+-------------------+
For Highlighted entry -> Entry not exist in TABLE1 and created timestamp taken from TABLE2
TIME1 in the second row should be taken from TABLE2
I tried somethink like below. It is doing cartesian product and return two many rows
select
table2.id table2id,
case when t2.logtype = 'PENDINGTIMESTAMP' then t2.created else table2.created end as time1,
case when t1.logtype = 'NEWTIMESTAMP' then t1.created else table2.created end as time2
from
table2,
table1 t1,
table1 t2
where
table2.id(+) = t1.table2id
and table2.id(+) = t2.table2id
i assume now, that table2 contains every possible table2id.
so I would create 2 outer joins from table2 to table1, one for pending and one for distributed timestamps.
finally, on selecting we can use the NVL function to use the created timestamp as fallback value.
SELECT m.id AS table2id,
NVL(p.created, m.created) AS time1,
NVL(d.created, m.created) AS time2
FROM table2 m
LEFT OUTER JOIN table1 p ON (p.table2id = m.id AND p.type = 'PENDINGTIMESTAMP')
LEFT OUTER JOIN table1 d ON (d.table2id = m.id AND d.type = 'DISTRIBUTEDTIMESTAMP')
or with Oracle outer join syntax (I'm not sure if the IS NULL is really necessary to compensate missing rows):
SELECT m.id AS table2id,
NVL(p.created, m.created) AS time1,
NVL(d.created, m.created) AS time2
FROM table2 m,
table1 p,
table1 d
WHERE m.id = p.table2id(+)
AND p.type(+) = 'PENDINGTIMESTAMP'
AND m.id = d.table2id(+)
AND d.type(+) = 'DISTRIBUTEDTIMESTAMP'
please note: I do not have a Oracle System to test the statement at hand, and I haven't used Oracle SQL syntax for about 3 years now. So please excuse, if there are syntactical errors.
But I hope, you get the idea.

Update with sum

I have a table with the following fields:
ID, VALUES, VARIAB
Im trying to SUM the field VALUES, but it needs to be grouped by ID.
And the Subselect doesnt accept multiple lines. (When i use it with just 1 ID, works fine).
BEGIN
UPDATE TBL2
SET SOMA =
(SELECT SUM(x.VALUES)
FROM TBL3 x INNER JOIN TBL2 y
ON y.ID = x.ID
WHERE y.ID = x.ID AND X.VARIAB = 1
GROUP BY x.ID
);
END;
Im using ORACLE DB, if anyone comment this ill be very gratefull.
Sorry for my english flaws.
To update multiple records at once and/or do an upsert, use MERGE statement like this :
MERGE INTO TBL2 T2 USING (
SELECT x.id,SUM(x.VALUES) total
FROM TBL3 x
WHERE x.VARIAB = 1
GROUP BY x.ID
) T3 ON (T2.ID = T3.ID)
WHEN MATCHED THEN UPDATE
SET T2.SOMA = T3.TOTAL
The issue is that your update statement isn't correlated - ie. your subquery has no reference to the table being updated.
You could change it to:
update tbl2 t2
set soma = (select sum(t3.values)
from tbl3 t3
where t2.id = t3.id
and t3.variab = 1);

Return non-null value from two tables in Oracle

I have two tables, T1 and T2 with same set of columns. I need to issue a query which will return me value of columns from either table whichever is not null. If both columns are null return null as the value of that column.
The columns are c1,c2,c3,cond1.
I issued the following query. The problem is that if one subquery fails the whole query fails. Somebody please help me. Probably there is another simple way.
SELECT NVL(T1.c1, T2.c1) c1,NVL(T1.c2, T2.c2) c2,NVL(T1.c3, T2.c3) c3
FROM (SELECT c1,c2,c3
FROM T1
WHERE cond1 = 'T10') T1
,(SELECT c1,c2,c3
FROM T2
WHERE cond1 = 'T200') T2 ;
You need something like this:
SELECT NVL((SELECT T1.c1
FROM T1
WHERE T1.c2 = 'T10'),
(SELECT T2.c1
FROM T2
WHERE T2.c2 = 'T200')) AS c1
FROM dual
Or you may prefer a full outer join:
SELECT NVL(T1.c1, T2.c1) AS c1
FROM T1 FULL OUTER JOIN T2 ON 1=1
WHERE T1.c2 = 'T10'
AND T2.c2 = 'T200'
Your result is logical. If the first table is null no combination of values will exist in the natural join.
EDIT. After some new requirements we can use a hack to get the row. Lets get all three possibilities, T1, T2 or all nulls and select the first one:
SELECT *
FROM ( (SELECT T1.*
FROM T1
WHERE T1.c2 = 'T10')
UNION ALL
(SELECT T2.*
FROM T2
WHERE T2.c2 = 'T200')
UNION ALL
(SELECT T2.*
FROM dual
LEFT JOIN T1 ON 1 = 0 ) )
WHERE ROWNUM = 1

Resources