How to join 2 tables without an ON clause - mysql

I want to get the SUM(column_a) from two different tables, and get their difference. I am using MySQL.
Table A's sum = 1234
Table B's sum = 4001
I'm not sure what to put in my ON clause:
SELECT
SUM(a.column1) AS table_a_sum,
SUM(b.column1) AS table_b_sum,
SUM(a.column1) - SUM(b.column1) AS difference
FROM table_a a
JOIN table_b b
ON ??????

A join without condition is a cross join. A cross join repeats each row for the left hand table for each row in the right hand table:
FROM table_a a
CROSS JOIN table_b b
Note that in MySQL, cross join / join / inner join are identical. So you could write:
FROM table_a a
JOIN table_b b
As long as you omit the on clause, this will work as a cross join.
If you'd like to sum two columns from two tables, a cross join would not work because it repeats rows. You'd get highly inflated numbers. For sums, a better approach uses subqueries, per #sgeddes answer.

Here's one option using subqueries -- there are several ways to do this:
SELECT
table_a_sum,
table_b_sum,
table_a_sum - table_b_sum AS difference
FROM
(SELECT SUM(column1) table_a_sum FROM table_a) a,
(SELECT SUM(column1) table_b_sum FROM table_b) b

You want to summarize first and then do the calculations:
select a.suma, b.sumb, a.suma - b.sumb
from (select sum(a.column1) as suma from tablea) a cross join
(select sum(b.column1) as sumb from tableb) b
Doing the cross join between the tables will generate a cartesian product that will mess up your sums.

Related

MySQL joining 3 tables on a column keeping all its distinct values

I want to join 3 tables:
Table A: Date, CountOfHonda(Integer)
Table B: Date, CountOfToyota(Integer)
Table C: Date, CountOfMazda(Integer)
I want the result table as: Date, CountOfHonda,CountOfToyota,CountOfMazda
All the dates might not be present in all 3 tables. I want to, in a sense, combine the tables without eliminating or duplicating any date value in the final table. If a Date is missing in a table, the value of the corresponding count column can be null/0. Thanks!
use full outer join simulation.
basically you do this:
SELECT * FROM tableA
LEFT JOIN tableB ON tableA.Date = tableB.Date
UNION
SELECT * FROM tableA
RIGHT JOIN tableB ON tableA.Date = tableB.Date
UNION
SELECT * FROM tableA
LEFT JOIN tableC ON tableA.Date = tableC.Date
UNION
SELECT * FROM tableA
RIGHT JOIN tableC ON tableA.Date = tableC.Date
don't worry about the dates which are not present in other tables. that's what the "outer" join is for. it would still keep those rows.
Edit: forgot mysql didn't have a full outer join. but this should take care of your query.
What you want is a tally (or lookup) table, for instance, DateLookupTable.
This table would have a single column, Date, with values from 01/01/1900 - 12/31/2099 (or whatever range is appropriate.
Then you do..
select d.Date, a.CountOfHonda, b.CountOfToyota, c.CountOfMazda
from DateLookupTable d
left join tableA a on a.Date = d.Date
left join tableB b on b.Date = d.Date
left join tableC c on c.Date = d.Date
where d.Date between (startDate) and (endDate)
Tally/lookup tables are invaluable in many situations.

Can't understand. Is this a subquery?

I have something in a query that I have to edit, that I don't understand.
There are 4 tables that are joined: tickets, tasks, tickets_users, users. The whole query is not important, but you have an example at the end of the post. What bugs me is this kind of code used many times in relation to other tables:
(SELECT name
FROM users
WHERE users.id=tickets_users.users_id
) AS RequesterName,
Is this a subquery with the tables users and tickets_users joined? What is this?
WHERE users.id=tickets_users.users_id
If this was a join I would have expected to see:
ON users.id = tickets_users.users_id
And how is this different from a typical join? Just use the same column definition: users.name and just join with the users table.
Can anyone enlighten me on the advanced SQL querying prowess of the original author?
The query looks like this:
SELECT
description,
(SELECT name
FROM users
WHERE users.id = tickets_users.users_id) AS RequesterName,
(SELECT description
FROM tickets
WHERE tickets.id = ticket_tasks.tickets_id) AS TicketDescription,
ticket_tasks.content AS TaskDescription
FROM
ticket_tasks
RIGHT JOIN
tickets ON ticket_tasks.tickets_id = tickets.id
INNER JOIN
tickets_users ON tickets_users.tickets_id = tickettasks.tickets_id
Thanks,
This is what is called a correlated subquery. To describe it in simple terms its doing a select inside a select.
However doing this more than once in ANY query is not recommended AT ALL.. the performance issue with this will be huge.
A correlated subquery will return a row by row comparison for each row of the select... if that doesnt make sense then think of it this way...
SELECT
id,
(SELECT id FROM tableA AS ta WHERE ta.id > t.id)
FROM
tableB AS t;
This will do for each row in tableB, every row in tableA will be selected and compared to tableB id.
NOTE:
If you have 100 rows in all 4 tables and you do a correlated subquery for each one then you are doing 100*100*100*100 row comparisons. thats 100,000,000 (one hundred million) comparisons!
A correlated subquery is NOT a join, but rather a subquery..
SELECT *
FROM
(SELECT id FROM t -- this is a subquery
) AS temp
However, JOINs are different... generally you can do it one of these two ways
This is the faster way
SELECT *
FROM t
JOIN t1 ON t1.id = t.id
This is the slower way
SELECT *
FROM t, t1
WHERE t1.id = t.id
what the second join is doing is making the Cartesian Product of the two tables and then filtering out the extra stuff in the WHERE clause as opposed to the first JOIN that filters as it joins.
For the different types of joins theres a few and all are useful in their prospective actions..
INNER JOIN (same as JOIN)
LEFT JOIN
RIGHT JOIN
LEFT OUTER JOIN
RIGHT OUTER JOIN
In mysql FULL JOIN or FULL OUTER JOIN does not exist.. so in order to do a FULL join you need to combine a LEFT and RIGHT join. See this link for a better understanding of what joins do with Venn diagrams LINK
REMEMBER this is for SQL so it includes the FULL joins as well. those don't work in MySQL.

SQL add rows count from a second table to the main query

I'm trying to improve a (not so much) simple query:
I need to retrieve every row from Table A.
Then join Table A with Table B so I get all the data I need.
At the same time, I need to add an extra column with the count() from Table C.
Something like:
SELECT a.*,
(SELECT Count(*)
FROM table_c c
WHERE c.a_id = a.id) AS counter,
b.*
FROM table_a a
LEFT JOIN table_b b
ON b.a_id = a.id
This works, ok, but in reality, I'm just making 2 queries and I need to improve this so it only do one (if, its even possible).
Anyone knows how can I achive that?
The simplest approach is likely to just move the correlated sub-query into a sub-query.
NOTE: Many optimisers deal with correlated sub-queries extremely effectively. Your example query could be perfectly reasonable.
SELECT
a.*,
b.*,
c.row_count
FROM
table_a a
LEFT JOIN
table_b b
ON b.a_id = a.id
LEFT JOIN
(
SELECT
a_id,
Count(*) row_count
FROM
table_c
GROUP BY
a_id
)
c
ON c.a_id = a.id
Another Note: SQL is an expression, it is not executed directly, it is translated into a plan using nest loops, hash joins, etc. Do not assume that having two queries is a bad thing. In this case my example may significantly minimise the number of reads compared to a single query and then use of GROUP BY and COUNT(DISTINCT).
Try this:
SELECT
tmp.*,
SUM(IF(c.a_id IS NULL,0,1)) as counter,
FROM (
SELECT
a.id as aid,
b.id as bid,
a.*,
b.*
FROM
table_a a
LEFT JOIN table_b b
ON b.a_id = a.id
) as tmp
LEFT JOIN table_c c
ON c.a_id = tmp.id
GROUP BY
tmp.aid,
tmp.bid

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.

MySQL, merging 2 or more tables before execute SELECT DISTINCT query?

I want to calculate how many unique logins from 2 (or probably more tables).
I tried this:
SELECT count(distinct(l1.user_id))
FROM `log_1` l1
LEFT JOIN `log_2` l2
ON l1.userid = l2.userid;
But it gives me result of l1. If I didn't put l1 on li.userid (distinct), it said "ambiguous".
How do I combine the table, and then select unique login of the combined table?
EDIT:
Tested: I test the count(distinct(l1.userid)) and count(distinct(l2.userid)). It gives me different result
If you are using LEFT JOIN then you will get at least one row in the combined result for each row in l1, so the join is entirely unnecessary if you just want a distinct count. This would give you the same result as your query:
SELECT count(distinct(l1.user_id))
FROM `log_1` l1
Perhaps you want an INNER JOIN or UNION instead? A UNION will count a user if they appear in either table. An INNER JOIN will count them only if they appear in both tables. Here's an example of the UNION:
SELECT count(*) FROM (
SELECT distinct(user_id) FROM `log_1`
UNION
SELECT distinct(user_id) FROM `log_2`
) T1