I have Table1 and Table2 related on Table1.ID. There can be zero or more Table2 records for a given Table1.ID. I have a view where I want to get Table2.Value where Table2.ID is max for a given Table1.ID. A friend suggested a derived table, but that requires a subquery in the from clause, and MySQL doesn't like that. Are there any other ways to do this? I tried setting up a secondary view to take the place of the subquery, but it seems very slow. I also tried using a having clause to test Table2.ID = MAX(Table2.ID), but it doesn't recognize the column unless I put it into the group by, which screws everything else up.
SELECT t1.*, t2a.*
FROM Table1 t1
LEFT JOIN Table2 t2a
ON (t1.table1_id = t2a.table1_id)
LEFT JOIN Table2 t2b
ON (t1.table1_id = t2b.table1_id AND t2a.table2_id < t2b.table2_id)
WHERE t2b.table2_id IS NULL
AND t1.table1_id = ?;
Related
i would like to know if there is any shortcut to specify the column where IN have to check for matches.
Example:
Instead of this:
select *
from table1
where id in(
select column
from table2
)
something like this:
select *
from table1
where id in table2.column
I know the existence of TABLE for IN, ANY, SOME to specify a table, but it works only if the table specified is composed by just 1 column
EDIT: using join is not an option, because the real use i was looking for is on a NOT IN operator, and also JOIN create duplicates sometimes like in a one to many relation
There is no shortcut like that in SQL. Let me explain why.
In a query, all table references need to be made in the FROM clause. Hence, you cannot simply refer to table2.col unless table2 has been defined in the FROM clause. table2 is actually an alias, which defaults to the table name.
From a performance perspective, I would recommend exists:
select t1.*
from table1 t1
where exists (select column
from table2 t2
where t2.column = t1.id
)
In particular, this can take advantage of an index on table2(column) and has the same semantics as in.
Using a JOIN is a bit shorter. At least it does not require a subquery or another SELECT ... FROM.
SELECT table1.*
FROM table1
JOIN table2 ON table1.id = table2.column
Although this simple example is an inner join, not a semi-join. An inner join is different because it produces one row per matched row in table2. A semi-join only produces one row for each row in table1, even if it matches multiple rows in table2.
If you want to simulate a semi-join, use DISTINCT to reduce the result to one row per row of table1:
SELECT DISTINCT table1.*
FROM table1
JOIN table2 ON table1.id = table2.column
If you want to check for something like NOT EXISTS, use an exclusion join:
SELECT table1.*
FROM table1
LEFT OUTER JOIN table2 ON table1.id = table2.column
WHERE table2.column IS NULL
No need to use DISTINCT on the outer join example. There will be no row duplication from the join, because it can only "match no rows" once.
I've never done an inner join SQL statement before, so I don't even know if this is the right thing to use, but here's my situation.
Table 1 Columns: id, course_id, unit, lesson
Table 2 Columns: id, course_id
Ultimately, I want to count the number of id's in each unit in Table 1 that are also in Table 2.
So, even though it doesn't work, maybe something like....
$sql = "SELECT table1.unit, COUNT( id ) as count, table2.id, FROM table1, table2, WHERE course_id=$im_course_id GROUP BY unit";
I'm sure the syntax of what I'm wanting to do is a complete fail. Any ideas on fixing it?
SELECT unit, COUNT( t1.id ) as count
FROM table1 as t1 inner JOIN table2 as t2
ON t1.id = t2.id
GROUP BY unit
hope this helps.
If I understand what you want (maybe you could post an example input and output?):
SELECT unit, COUNT( id ) as count
FROM table1 as t1 JOIN table2 as t2
ON t1.id = t2.id
GROUP BY unit
Okay, so there are a few things going on here. First off, commas as joins are deprecated so they may not even be supported (depending on what you are using). You should probably switch to explicitly writing inner join
Now, whenever you have any sort of join, you also need on. You need to tell sql how it should match these two tables up. The on should come right after the join, like this:
Select *
From table1 inner join table2
on table1.id = table2.id
and table1.name = table2.name
You can join on as many things as you need by using and. This means that if the primary key of one table is several columns, you can easily create a one-to-one match between tables.
Lastly, you may be having issues because of other general syntax errors in your query. A comma is used to separate different pieces of information. So in your query,
SELECT table1.unit, COUNT( id ) as count, table2.id, FROM ...
The comma at the end of the select shouldn't be there. Instead this should read
SELECT table1.unit, COUNT( id ) as count, table2.id FROM ...
This is subtle, but the sql query cannot run with the extra comma.
Another issue is with the COUNT( id ) that you have. Sql doesn't know which id to count since table1 and table2 both have ids. So, you should use either count(table1.id) or count(table2.id)
Let's say I have a mastertable (table1) with a detailtable (table2). There can be multiple detail records for each masterrecord. Now I want a query that counts all detailrecords for each masterrecord :
SELECT t1.id, count(t2.*)
FROM table1 as t1
LEFT JOIN table2 AS t2 ON t2.id=t1.id
GROUP BY t1.id
This gives me exactly the same number of records as table1 has.
But when I add a WHERE statement to only count the records that have a checkfield that's higher than 0, I don't get all records in table1 anymore! The ones with no matching detailrecords are now left out completely. Why is this happening?
SELECT t1.id, count(t2.*)
FROM table1 as t1
LEFT JOIN table2 AS t2 ON t2.id=t1.id
WHERE t2.checkfield != 0
GROUP BY t1.id
(Maybe something else is wrong in my real query, since I tried to simplify it for this example, but I think I got it right)
The WHERE clause restricts the joined results which are being aggregated over, so while you're trying do an outer join, only those rows with t2.checkfield != 0 survive, but that excludes all the unmatched rows!
On the other hand, when you change WHERE to AND, you now have tab1 LEFT OUTER JOIN tab2 ON(tab1.id = tab2.t1_id AND some_condition) -- but this is still an outer join, i.e. records on the left which have no match on the right will be included.
Is it possible in MySQL to change the JOIN of a table based on whats in a particular field of a record?
Example:
SELECT
CASE table0.status
WHEN 1 THEN table1.id
WHEN 2 THEN table2.id
END
FROM
table0, table1, table2
IF (table0.status = 1, INNER JOIN queue ON table1.id = table0.product, INNER JOIN queue ON table2.id = table0.product)
I need the joined table to be table1 if the value for 'product' in table0 = 1 or table2 if the value for 'product' in table0 is 2.
When I try the above example I only get mysql syntax errors. Ive also tried it with CASE statement instead of the IF but still not working.
I think a subselect will be a better solution than JOIN in this case. You can use a CASE statement with a SELECT inside it.
I'm sure this is straight-forward, but how do I write a query in mysql that joins two tables and then returns only those records from the first table that don't match. I want it to be something like:
Select tid from table1 inner join table2 on table2.tid = table1.tid where table1.tid != table2.tid;
but this doesn't seem to make alot of sense!
You can use a left outer join to accomplish this:
select
t1.tid
from
table1 t1
left outer join table2 t2 on
t1.tid = t2.tid
where
t2.tid is null
What this does is it takes your first table (table1), joins it with your second table (table2), and fills in null for the table2 columns in any row in table1 that doesn't match a row in table2. Then, it filters that out by selecting only the table1 rows where no match could be found.
Alternatively, you can also use not exists:
select
t1.tid
from
table1 t1
where
not exists (select 1 from table2 t2 where t2.tid = t1.tid)
This performs a left semi join, and will essentially do the same thing that the left outer join does. Depending on your indexes, one may be faster than the other, but both are viable options. MySQL has some good documentation on optimizing the joins, so you should check that out..