I have to write a custom interpreter that simulates SQL select queries on a database with three tables: A, B, and C. My question is as follows: do the following queries return the same results?
select A1
from A
where A1 = 1;
select A1
from A, C
where A1 = 1;
As I have it written, these two provide different results, because of the added table in the from clause. But I'm not sure if that's right; should the results depend on the tables in the from clause or the joins (or lack thereof) in the where clause?
The Second will return all the rows matching de A where Clause and all the row from the C table. Since there is no relation defined between those table. It's often call a cartesian product.
If you want a relation between A and C you will need a join between those, such as A.C_ID = C.ID for a matching pattern, or LEFT | RIGHT join depending on the set of result you want.
Related
What will happen in an Oracle SQL join if I don't use all the tables in the WHERE clause that were mentioned in the FROM clause?
Example:
SELECT A.*
FROM A, B, C, D
WHERE A.col1 = B.col1;
Here I didn't use the C and D tables in the WHERE clause, even though I mentioned them in FROM. Is this OK? Are there any adverse performance issues?
It is poor practice to use that syntax at all. The FROM A,B,C,D syntax has been obsolete since 1992... more than 30 YEARS now. There's no excuse anymore. Instead, every join should always use the JOIN keyword, and specify any join conditions in the ON clause. The better way to write the query looks like this:
SELECT A.*
FROM A
INNER JOIN B ON A.col1 = B.col1
CROSS JOIN C
CROSS JOIN D;
Now we can also see what happens in the question. The query will still run if you fail to specify any conditions for certain tables, but it has the effect of using a CROSS JOIN: the results will include every possible combination of rows from every included relation (where the "A,B" part counts as one relation). If each of the three parts of those joins (A&B, C, D) have just 100 rows, the result set will have 1,000,000 rows (100 * 100 * 100). This is rarely going to give the results you expect or intend, and it's especially suspect when the SELECT clause isn't looking at any of the fields from the uncorrelated tables.
Any table lacking join definition will result in a Cartesian product - every row in the intermediate rowset before the join will match every row in the target table. So if you have 10,000 rows and it joins without any join predicate to a table of 10,000 rows, you will get 100,000,000 rows as a result. There are only a few rare circumstances where this is what you want. At very large volumes it can cause havoc for the database, and DBAs are likely to lock your account.
If you don't want to use a table, exclude it entirely from your SQL. If you can't for reason due to some constraint we don't know about, then include the proper join predicates to every table in your WHERE clause and simply don't list any of their columns in your SELECT clause. If there's a cost to the join and you don't need anything from it and again for some very strange reason can't leave the table out completely from your SQL (this does occasionally happen in reusable code), then you can disable the joins by making the predicates always false. Remember to use outer joins if you do this.
Native Oracle method:
WITH data AS (SELECT ROWNUM col FROM dual CONNECT BY LEVEL < 10) -- test data
SELECT A.*
FROM data a,
data b,
data c,
data d
WHERE a.col = b.col
AND DECODE('Y','Y',NULL,a.col) = c.col(+)
AND DECODE('Y','Y',NULL,a.col) = d.col(+)
ANSI style:
WITH data AS (SELECT ROWNUM col FROM dual CONNECT BY LEVEL < 10)
SELECT A.*
FROM data a
INNER JOIN data b ON a.col = b.col
LEFT OUTER JOIN data c ON DECODE('Y','Y',NULL,a.col) = b.col
LEFT OUTER JOIN data d ON DECODE('Y','Y',NULL,a.col) = d.col
You can plug in a variable for the first Y that you set to Y or N (e.g. var_disable_join). This will bypass the join and avoid both the associated performance penalty and the Cartesian product effect. But again, I want to reiterate, this is an advanced hack and is probably NOT what you need. Simply leaving out the unwanted tables it the right approach 95% of the time.
I have 2 database tables. Table A has to fetch some records based on parameter passed there may or may not be an entry in table B with that key.
What I want to do is:
select a.col1,a.col2,a.col3
FROM table WHERE a.id = 123
This would fetch 20 rows. For one of the rows there is an entry in another table B.
select T_level from table b where b.id = 123
only one record appears with right value.
What I want is to get this in a single query. Something like:
select a.col1,a.col2,a.col3,b.T_level
from a,b
where a.id = 123
and a.id = b.id
When I do that, I get 20 rows and the column T_level as '50' for all the rows, whereas it should be '50' for one correct row, for rest it should be null.
I further tried:
select a.col1,a.col2,a.col3,nvl(b.T_level,0) from a,b
but that doesn't fetch the way I expect.
Firstly, please learn to use ansi sql join syntax. The Oracle join syntax you are using hasn't been considered good practice for decades
SQL Join syntax
If you want to get all records from a and any matching records from b then you need to use a LEFT OUTER JOIN
Can someone explain to me why the below query is returning null in the description field
Table A:
OCD CCD
A B
C D
E F
Table B:
CD DESCRIP
A AL
B BL
C CL
D DL
E EL
F FL
Result:
OCD DESCRIP CCD DESCRIP
A AL B BL
C CL D DL
E EL F FL
Incorrect Query:although this query runs correctly. It doesn't give description values.
select a.ocd,b.DESCRIP,a.CCD,b.DESCRIP
from A a, B b
where a.ocd=b.cd(+)
and a.ccd=b.cd(+);
Correct query
select a.ocd,b.DESCRIP,a.CCD,b.DESCRIP
from A a, B b1, B b2
where a.ocd=b1.cd(+)
and a.ccd=b2.cd(+);
You need to look up the values twice because you have two codes. This requires two joins, which should be left joins if there is a possibility of non-matches:
select a.ocd, b1.DESCRIP, a.CCD, b2.DESCRIP
from A left join
B b1
on a.ocd = b1.cd left join
B b2
on a.ccd = b2.cd;
The conditions in your first query are:
where a.ocd=b.cd(+) and a.ccd=b.cd(+);
Just look at them. They imply that in any matching row, a.ocd = a.ccd, and that is not true on any rows in your data. Hence, there is no match and the result is NULL.
Also, learn to use proper explicit JOIN syntax. Explicit joins are more powerful, more portable, and easier to read. Further, Oracle deprecated the (+) syntax many years ago, meaning that even Oracle may not support it in the future.
From what you call the "correct query" it seems you want to select each row from table A, and then for each value in that row, the corresponding value in a row in Table B. In the first query, where you join table A and table B, the join condition requires that both values from the row in table A are matched IN THE SAME ROW in table B. Clearly that doesn't meet your specification. If you want to match one row from table A with two (usually DIFFERENT) rows from table B, you need to join table A with table B twice, as in the correct query.
When you join two tables, all the combinations of ONE ROW from the first table and ONE ROW from the second table are checked to see if the join condition(s) is/are met. When you join three tables, all the combinations of ONE ROW from each of the three tables are checked against the join condition(s). This is why you need table B twice in your join: you want to combine one row from table A and TWO rows from table B for one row in the result.
You should translate your query to standard SQL:
select a.ocd, b.DESCRIPT, a.CCD, b.DESCRIPT
from a
left join b on a.ocd = b.cd and a.ccd = b.cd
i've been recently working in mysql and in one of the requests i wrote :
SELECT SIGLE_EEP, ID_SOUS_MODULE, LIBELLE
FROM mef_edi.eep a, mef_edi.envoi e, mef_edi.sous_module s
WHERE a.ID_EEP = e.ID_EEP
AND a.ID_SOUS_MODULE = s.ID_SOUS_MODULE;
and they told me :
Column ID_SOUS_MODULE in field list is ambiguous
What should i do ?
More than one table has a column named ID_SOUS_MODULE.
So you need to name the table every time you mention the column to specify which table you mean.
Change
SELECT ID_SOUS_MODULE
for instance to
SELECT a.ID_SOUS_MODULE
I agree with the answer above, you may have duplicate column names across your 3 tables, assigning the table id (a, e, s) as noted above will avoid that issue in the select. In addition to what #juergen said you may want to get rid of that cartesian join by using an inner or left join (inner seems to be what your going for). The way you are joining your table you are joining every possible combination of rows together than filtering. using a proper join will get you better performance in the long run as your table line counts grow. Here is an example of a non cartesian join:
SELECT SIGLE_EEP, ID_SOUS_MODULE, LIBELLE
FROM mef_edi.eep a
INNER JOIN mef_edi.envoi e ON (a.ID_EEP = e.ID_EEP)
INNER JOIN mef_edi.sous_module s ON (a.ID_SOUS_MODULE = s.ID_SOUS_MODULE)
I'm learning Access and SQL, but I have a problem using subqueries in the from clause I can't seem to figure out.
Select *
From (LongSubQuery) as a, (LongSubQuery) as b, (LongSubQuery) as c
Where a.field=b.field=c.field;
This works perfectly as long as each of the statements A, B, and C in the from clause returns a record. If the where clause in any of the three statements prevents the return of a record, then none of the statements will return a result. I've tried various NZ and is not null statements with no luck. I'm suspicious it is actually caused by the last line of code making the fields equivalent. Is there any way around this?
First of all, when you do something like select * from A, B, C (where A, B, C are data sets), you are returning the cartesian product of A, B, C; in other words, you will have #(A)*#(B)*#(C) rows (where #(A) is the number of rows in set A). So, of course, if one of the sets is empty, the whole set is empty.
Possible solution: Use unilateral joins:
select *
from
(select ...) as a
left join (select ...) as b on a.aField = b.aField ...
left join (select ...) as c on b.aField = c.aFiedl ...
left join returns all the rows on the left side of the relation and all the matching rows of the right side of the relation if it is fulfilled, and null values if it is not fulfilled.
Be careful when you make the relations. Be sure you use the fields you need. Notice that in this case you can define the condition you are using in the where clause directly in the join construction.