Explaining MySQL query with multiple tables listed in FROM - mysql

a, b are not directly related.
What does a,b have to do with the results?
select * from a,b where b.id in (1,2,3)
can you explain sql?

Since you haven't specified a relationship between a and b, this produces a cross product. It's equivalent to:
SELECT *
FROM a
CROSS JOIN b
WHERE b.id IN (1, 2, 3)
It will combine every row in a with the three selected rows from b. If a has 100 rows, the result will be 300 rows.

What you using is Multitable SELECT.
Multitable SELECT (M-SELECT) is similar to the join operation. You
select values from different tables, use WHERE clause to limit the
rows returned and send the resulting single table back to the
originator of the query.
The difference with M-SELECT is that it would return multiply tables
as the result set. For more deatils: https://dev.mysql.com/worklog/task/?id=358
In other word, you query is :
SELECT *
FROM a
CROSS JOIN b
WHERE b.id in (1,2,3)

Related

Generate list of distinct dimensions in a table

I have a table with 3 dimensions- A, B, and C.
I essentially want values of all possible combinations for these dimensions and populate all measures(M) as 0 when a combination isn't present.
Suppose I have the table-
If I do this I get -
select a,b,c from sum(m) fact group by a,b,c
But I would like all possible combinations, -
Currently, I a doing a cross join like below, but is there some faster way to do this (as my table has about ~1M records)? -
select * from (
select distinct f1.a, f2.b, f3.c
from fact f1
cross join fact f2
cross join fact f3 ) all
left join
( select a,b,c from sum(m) fact group by a,b,c) s
on all.a=s.a and all.b=s.b and all.c=s.c
If this is Oracle Database, then this is exactly what cube is for.
select a, b, c, sum(m)
from my_table
group by cube(a,b,c)
MySQL:
GROUP BY a,b,c will produce 1 row per combination that exists in the table.
If you want all possible combinations, you need to build 1 (or 3) more tables to list all the possible values, then do a LEFT JOIN from them. You may also want COALESCE(col, 0) to turn NULLs into zeros.

Select Count from Two Tables = Multiplication in SQL?

I randomly tried running a query like:
select count(*) from table1, table2
The result was essentially multiplication of the actual row count of the two tables, i.e. the result was 645792 rows based on the fact that table1 had 868 rows, and table2 had 744 rows.
Is this an expected behaviour, I checked out the documentation but could not get any better understanding of this behaviour.
This is your from clause:
from table1, table2
This is equivalent to:
from table1 cross join table2
This is a cartesian product of both tables, which generates a resultset containing 868 * 744 rows. Then count(*) just counts the number of resulting rows, hence the result that you are getting.
If you wanted to sum the number of rows in each table, you would compute two separate counts:
select
(select count(*) from table1)
+ (select count(*) from table2) total_no_rows
Your current query:
select count(*) from table1, table2
is using the old school implicit join syntax. As there is no join criteria appearing in a WHERE clause (there is no WHERE clause), the join defaults to being a cross join. This is just the cross product between records in the two tables, which is what you are currently seeing. A better way to write your query would be:
SELECT COUNT(*)
FROM table1
CROSS JOIN table2;
'INNER JOIN and , (comma) are semantically equivalent in the absence of a join condition: both produce a Cartesian product' https://dev.mysql.com/doc/refman/8.0/en/join.html

How to join a derived table

I have a complex query which results in a table which includes a time column. There are always two rows with the same time:
The result also contains a value column. The value of two rows with the same time is always different.
I now want to extend the query to join the rows with the same time together. So my thought was to join the derived table like this:
SELECT A.time, A.value AS valueA, B.value as valueB FROM
(
OLD_QUERY
) AS A INNER JOIN A AS B ON
A.time=B.time AND
A.value <> B.value;
However, the JOIN A AS B part of the query does not work. A is not recognized as the derived table. MySQL is searching for a table A in the database and does not find it.
So the question is: How can I join a derived table?
You cannot join a single reference to a table (or subquery) to itself; a subquery must be repeated.
Example: You cannot even do
SELECT A.* FROM sometable AS A INNER JOIN A ...
The A after the INNER JOIN is invalid unless you actually have a real table called A.
You can insert the subquery's results into another table, and use that; but it cannot be a true TEMPORARY table, as those cannot be joined to themselves or referenced twice at all in almost any query. _By referenced twice, I mean joined, unioned, used as an "WHERE IN" subquery when it is already referenced in the FROM.
If nothing else distinguishes the rows, you can just use aggregation to get the two values:
select time, min(value), max(value)
from (<your query here>) a
group by time;
In MySQL 8+, you can use a cte:
with a as (
<your query here>
)
select a1.time, a1.value, a2.value
from a a1 join
a a2
on a1.time = a2.time and a1.value <> a2.value;

join two different tables?

How can I join table a and table b and get records for each? Not an actual join... not sure what this is called.
So if I have 3 records in a, and 5 records in b, I want 8 records back.
In a record for a, all b fields can be null. In a record for b, all a fields can be null.
edit: My tables have different fields.
Error Code: 1222. The used SELECT statements have a different number of columns
Like the others mentionned, you need an union
SELECT intColumn, varcharColumn, intColumn FROM a
UNION
SELECT intColumn, varcharColumn, 0 FROM b
but you must have the same number of columns and they must also have similar data types.
Here's a good tutorial about it
Also, if you want columns that are not in both tables, you can fill with nulls or constants.
You want a UNION:
SELECT something FROM a
UNION
SELECT something FROM b
Try this
SELECT * FROM a
LEFT JOIN b ON a.id1 = b.id2
UNION
SELECT * FROM a
RIGHT JOIN b ON a.id1 = b.id2
Just make sure, that A and B have different IDs
Edit: Working Fiddle
You can also use some other field other then id which are not same in two table
Edit: Updated fiddle

Transforming a Complicated Requirement into a SQL Query

I am having trouble with the relational algebra and transformation into SQL of this rather complicated query:
I need to select all values from table A joined to table B where there are no matching records in table B, or there are matching records but the set of matching records do not have a field that contains one of 4 of a possible 8 total values.
Database is MySQL 5.0... using an InnoDB engine for the tables.
Select
a.*
from
a
left join
b
on
a.id=b.id
where
b.id is null
or
b.field1 not in ("value1","value2","value3","value4");
I'm not sure if there is any real performance improvement but one other way is:
SELECT
*
FROM
tableA
WHERE
id NOT IN ( SELECT id FROM tableB WHERE field1 NOT IN ("value1", "value2"));
Your requirements are a bit unclear. My 1st interpretation is that you only want the A columns, and never more than 1 instance of a given A row.
select * from A where not exists (
select B.id
from B
where B.id=A.id
and B.field in ('badVal1','badVal2','badVal3','badVal4')
)
My 2nd interpretation is you want all columns from (A outer joined to B), with perhaps more than one instance of an A row if there are multiple B rows, as long as not exists B row with forbidden value.
select * from A
left outer join B on A.id=B.id
where not exists (
select C.id
from B as C
where A.id=C.id
and C.field in ('badVal1','badVal2','badVal3','badVal4')
)
Both queries could be expressed using NOT IN instead of correlated NOT EXISTS. Its hard to know which would be faster without knowing the data.