Ora SQL Query: joining without references - sql

I am trying to achieve some logic on Oracle by using simple query and feeling stuck on it. The thing is that I cannot use PL-SQL and this is giving me some headached.
I have three tables with below values
I am trying to get something like:
SELECT T1.CODE,T2.CODE,T3.VALUE
FROM TABLE1 T1
JOIN TABLE2 T2 ON T1.REF = T2.CODE
JOIN TABLE3 T3 ON T2.REF = T3.CODE
WHERE T1.CODE = XXXXX
Result for XXXX = 98
98,2,CCC
Whenever the parameter XXXXX is 99,98,96,95 it returns what I was expecting but the logic I need doesnt work for 97.
My requirement says that in case i cannot find a link in Table2 then I should use always DEF in Table3 and leave unlinked values as NULL. Something like:
Result for XXXX = 97
97,NULL,AAA
I think it could be achieved in a not very "clean" way by using CASE statements but this is an example in which the number of columns shown is very minimal. In my real case it is extremelly bigger... So I want to try to avoid using CASE statements as it would raise the complexity of it a lot.
I tried with different methods but my low experience on Oracle cannot deep so much :)
Any way to achieve this without using PLSQL neither those CASE?

If I'm understanding correctly, you need to use an outer join instead. You can then use COALESCE to return the value associated with "DEF" if T2.REF is NULL:
SELECT T1.CODE,
T2.CODE,
T3.VALUE
FROM TABLE1 T1
LEFT JOIN TABLE2 T2 ON T1.REF = T2.CODE
LEFT JOIN TABLE3 T3 ON COALESCE(T2.REF,'DEF') = T3.CODE
WHERE T1.CODE = XXXXX

Related

How can this query be optimized please?

I have performence issues with the following query :
SELECT A,B,C,D,E,F
FROM TABLE1 T1
INNER JOIN TABLE2 T2
ON (((T1.E IS NULL OR T2.E IS NULL) AND T1.F= T2.F)
OR((T1.E IS NOT NULL OR T2.E IS NOT NULL) AND T1.E = T2.E))
More than 30 min to return about 1000 rows
I've tried this :
SELECT A,B,C,D,E,F
FROM TABLE1 T1
INNER JOIN TABLE2 T2
ON (((COALESCE(T1.E,-1) = COALESCE(T2.E,-1)
AND ((T1.F= T2.F)
OR(T1.E = T2.E)))))
but gives less results than the first one
Can you help me to find another way to write it in oreder to reduce execution time please ?
I'm using SQL Server 2016
Try this:
SELECT A,B,C,D,E,F
FROM TABLE1 T1
INNER JOIN TABLE2 T2 ON T1.F = T2.F
WHERE T1.E IS NULL OR T2.E IS NULL
UNION
SELECT A,B,C,D,E,F
FROM TABLE1 T1
INNER JOIN TABLE2 T2 ON T1.E = T2.E
WHERE COALESCE(T1.E, T2.E) IS NOT NULL
You might want a UNION ALL, but this should match the original.
This also exposes an interesting quirk in the original logic you may want to reconsider. If the E field from one table is NULL, but not the other, the original code would make checks on both the E and F fields. Which is interesting, because for the E field we know one side is null, but the other is not, so that case can't ever be true... but the logic says to still make the comparison.
It's hard to know what you're doing with the generic names, but there's definitely room to clean up that conditional check. Before worrying about matching to your first results, go back and make sure those first results clearly and accurately state what you want to accomplish, even if that means making the query even slower or longer.
Then, only when you are sure you have a query that both produces accurate results and describes them in an understandable way, you can start looking for different or clever ways to express the same logic that might perform better. But if you don't first take the step of better-defining your logic, you won't be able to validate your optimizations and you'll risk quickly producing incorrect data.
Non-equality conditions -- such as OR -- pretty much kill JOIN performance, especially in databases such as SQL Server that do not use indexes in such cases.
I would recommend a two-join approach, but you are going to have to fix the SELECT because it is not clear where the columns come from.
SELECT --A, B, C, D, E, F,
T1.A,
COALESCE(T2_1.B, T2_2.B) as B,
. . .
FROM TABLE1 T1 INNER JOIN
TABLE2 T2_1
ON T2.F = T1.F AND
(T1.E IS NULL OR T2_1.E IS NULL) LEFT JOIN
TABLE2 T2_2
ON T2_2.E = T1.E -- E cannot be NULL
WHERE T2_1.F IS NOT NULL OR T2_2.E IS NOT NULL; -- checks for a match for either condition
Then for performance, you want indexes on TABLE2(F, E) and TABLE2(E).
Statement OR might extremely decrease execution time. Try to get rid of it. Maybe something like this would do:
SELECT A,B,C,D,E,F
FROM TABLE1 T1
LEFT JOIN TABLE2 T2
ON T1.E = T2.E
LEFT JOIN TABLE2 T22
ON T1.F= T22.F
AND T2.E IS NULL
WHERE NOT (T2.E IS NULL AND T22.F IS NULL)

SQL Query Performance Join with condition

calling all sql experts. I have the following select statement:
SELECT 1
FROM table1 t1
JOIN table2 t2 ON t1.id = t2.id
WHERE t1.field = xyz
I'm a little bit worried about the performance here. Is the where clause evaluated before or after the join? If its evaluated after, is there way to first evaluate the where clause?
The whole table could easily contain more than a million entries but after the where clause it may be only 1-10 entries left so in my opinion it really is a big performance difference depending on when the where clause is evaluated.
Thanks in advance.
Dimi
You could rewrite your query like this:
SELECT 1
FROM (SELECT * FROM table1 WHERE field = xyz) t1
JOIN table2 t2 ON t1.id = t2.id
But depending on the database product the optimiser might still decide that the best way to do this is to JOIN table1 to table2 and then apply the constraint.
For this query:
SELECT 1
FROM table1 t1 JOIN
table2 t2
ON t1.id = t2.id
WHERE t1.field = xyz;
The optimal indexes are table1(field, id), table2(id).
How the query is executed depends on the optimizer. It is tasked with choosing the based execution plan, given the table statistics and environment.
Each DBMS has its own query optimizer. So by logic of things in case like yours WHERE will be executed first and then JOINpart of the query
As mentioned in the comments and other answers with performance the answer is always "it depends" depending on your dbms and the indexing of the base tables the query may be fine as is and the optimizer may evaluate the where first. Or the join may be efficient anyway if the indexes cover the join requirements.
Alternatively you can force the behavior you require by reducing the dataset of t1 before you do the join using a nested select as Richard suggested or adding the t1.field = xyz to the join for example
ON t1.field = xyz AND t1.id = t2.id
personally if i needed to reduce the dataset before the join I would use a cte
With T1 AS
(
SELECT * FROM table1
WHERE T1.Field = 'xyz'
)
SELECT 1
FROM T1
JOIN Table2 T2
ON T1.Id = T2.Id

Update with where ANSI join syntax in PostgreSQL updates all rows

I'm trying to do an update with joins in the where clause. I understand with PostgreSQL there is a from clause that I can use with implicit joins like this:
update tbl1 t1 set name = 'foo'
from tbl2 t2
where t2.id = t1.table2_id
and t2.region = 'bar'
However, I have existing code that generates ANSI joins instead of implicit joins. Looking around Stack Overflow, I read that I could do something like this:
update tbl1 set name = 'foo'
from tbl1 t1
inner join tbl2 t2 on t2.id = t1.table2_id
where t2.region = 'bar'
Unfortunately, this doesn't seem to work, and instead of updating just 2 rows, it updates all the rows, regardless of what's in the from/where clause.
What am I missing?
Yes that is a side effect that is caused due to the reason that it treats t1 as a different table than the one that is being updated. There are 2 ways of getting around this.
Use the first query that you posted to UPDATE.
Add a condition to the second query like tbl1.id = t1.id so that it forces 1 to 1 mapping of the table being updated.

I know how it looks in SQL, but I need it in HQL and am stuck

Consider I have such SQL query:
SELECT t1.* FROM table1 t1 LEFT JOIN table2 t2 ON t1.table2_id = t2.id
WHERE t2.value = 'something' OR t1.value = 'something';
I need the same thing done in HQL query.
More info: Say I have classes Table1 and Table2 both having field named value and Table1 having a field table2 of class Table2. What I want is to get a list of Table1 objects that have certain value or it's member table2 has certain value and I know that table2 field might be null.
I have tried to formulate the question as clearly as I could without trying to explain every single way I tried to do that without success. Sorry if it is not very clear.
Based on the description of the problem in the question, I assume that you have a parent class Table1 and a child class Table2. Table1 has a member table2 of type Table2. In this case, I believe, the appropriate HQL should look like this:
from Table1 t1 where t1.value = 'something' or t1.table2.value = 'something'
Working example:
select t1 from Table1 as t1 left outer join t1.table2 as t2
where t1.value = :value or t2.value = :value
Additional note:
If using grails one has to use executeQuery method as findAll will not be enough.
There may be other solutions that I do not know. If you want to share a better solution, please do.

Bulk Record Update with SQL

I have two tables in a SQL Server 2008 environment with the following structure
Table1
- ID
- DescriptionID
- Description
Table2
- ID
- Description
Table1.DescriptionID maps to Table2.ID. However, I do not need it any more. I would like to do a bulk update to set the Description property of Table1 to the value associated with it in Table2. In other words I want to do something like this:
UPDATE
[Table1]
SET
[Description]=(SELECT [Description] FROM [Table2] t2 WHERE t2.[ID]=Table1.DescriptionID)
However, I'm not sure if this is the appropriate approach. Can someone show me how to do this?
Your way is correct, and here is another way you can do it:
update Table1
set Description = t2.Description
from Table1 t1
inner join Table2 t2
on t1.DescriptionID = t2.ID
The nested select is the long way of just doing a join.
Your approach is OK
Maybe slightly clearer (to me anyway!)
UPDATE
T1
SET
[Description] = t2.[Description]
FROM
Table1 T1
JOIN
[Table2] t2 ON t2.[ID] = t1.DescriptionID
Both this and your query should run the same performance wise because it is the same query, just laid out differently.
You can do this through a regular UPDATE with a JOIN
UPDATE T1
SET Description = T2.Description
FROM Table1 T1
JOIN Table2 T2
ON T2.ID = T1.DescriptionId
Or you can simply update without using join like this:
Update t1 set t1.Description = t2.Description from #tbl2 t2,tbl1 t1
where t1.ID= t2.ID
The SQL you posted in your question is one way to do it. Most things in SQL have more than one way to do it.
UPDATE
[Table1]
SET
[Description]=(SELECT [Description] FROM [Table2] t2 WHERE t2.[ID]=Table1.DescriptionID)
If you are planning on running this on a PROD DB, it is best to create a snapshot or mirror of it first and test it out. Verify the data ends up as you expect for a couple records. And if you are satisfied, run it on the real DB.