MySQL JOIN Statement with Two Conditions - mysql

I have two tables both with columns called member_id. I'd like to select all member_ids...
WHERE end_date <= NOW() from table 1, and
approved='n' from table 2.
I'm very unfamiliar with JOIN, but I believe this is what's needed here. Something like this doesn't seem to be working though...
SELECT both.member_id, both.course_id
FROM vbc_status
INNER JOIN course_enrollment ON both.member_id=both.member_id AND
both.end_date <= NOW() AND
both.approved='n'
How can I make this happen?

You still have to reference the original columns by their source even after the join. I'm not sure which table has course_id so you'll have to fix that one before it will run.
SELECT vbc_status.member_id, ?.course_id
FROM vbc_status INNER JOIN course_enrollment
ON vbc_status.member_id = course_enrollment.member_id
AND vbc_status.end_date <= NOW() AND course_enrollment.approved = 'n'
You'd probably find table aliases to be handy.

I think you want this:
SELECT *
FROM vbc_status v
INNER JOIN course_enrollment c ON v.member_id = c.member_id
WHERE v.end_date <= NOW() AND c.approved='n'

SELECT t1.member_id, t1.course_id FROM vbc_status t1
JOIN course_enrollment ce USING(member_id)
WHERE t1.end_date <= NOW() AND ce.approved='n'
I assumed end_date is a column of vbc_status and approved is a column of course_enrollment.
Explanation of the statement:
You set up table aliases with vbc_status t1, this makes t1 the alias for the table vbc_status, and course_enrollment gets the alias ce.
Then on selecting you have to prefix the fields you want to see with the alias of the table, and the same goes for the where statement.

Related

Every derived table must have its own alias mysql

I have a temporary table named Days created as
CREATE TEMPORARY TABLE days (start_date DATETIME)as
SELECT DATE_ADD(begin_date, INTERVAL n - start_health_post_id DAY) as
start_date FROM NOF
ORDER BY n
LIMIT nofdays;
Now I want to have a cross join with a bunch of select statements that perform inner join
So, I tried this ways
Select * from days
cross join
(
Select practices.*, providers.*, practice_locations.*
from practices
Inner Join providers on practices.health_post_id = providers.health_post_id
Inner join practice_locations on practices.health_post_id =practice_locations.health_post_id
);
But It gives an error saying , every derived table must have its own alias.
please help!
Set an alias for your sub-query like:
Select * from days
cross join
(
Select practices.*, providers.*, practice_locations.*
from practices
Inner Join providers on practices.health_post_id = providers.health_post_id
Inner join practice_locations on practices.health_post_id =practice_locations.health_post_id
) t1;
I set t1 as alias.

I trying to use a sub query in MySQL, but is this the right approach?

I have 3 tables I need to pull from A,B,C (the data is not organized well)
I have used a JOIN on the first two tables but I an not sure how to proceed with the 3rd table. Is a sub query best or use another join?
any help? can I use 2 WHERE clause?
SELECT DISTINCT `App`,`status`,`New App`,`Sunset`
FROM `Table A`
LEFT JOIN `Table B`
ON `App (table A)`= `New App(Table B)`
WHERE status NOT LIKE '%sunset%'
This is Table C, it has the request date I need
(SELECT `App ID`,`Status`
FROM `requests`
WHERE `Updated` < DATE_SUB(NOW(), INTERVAL 364 DAY))
You can alias the tables when you join.
If they all share common identifiers, joining that's the fastest approach.
SELECT DISTINCT
a.App, b.status, c.NewApp AS c_new_apps
FROM
TableA a
LEFT JOIN
TableB b ON a.App = b.NewApp
LEFT JOIN
TableC c ON c.AppId = b.NewApp
WHERE
b.status NOT LIKE '%sunset%',
c.Updated` < DATE_SUB(NOW(), INTERVAL 364 DAY)
Also, consider if you are looking for INNER JOINs or OUTER JOINs.

Give an Alias to a Joined Table MySQL

Is it possible to give an alias to a joined table in MySQL?
For example
Select *
From Customers
Natural Join Transaction as CT
Where (Select Count(CT.Customer_ID) ) >= 2
Would CT reference the joined table or the Transaction table?
And if it references the Transaction table how do I reference the joined table in a sub query?
No, you cannot do this in MySQL. In other databases, you could use a CTE for this purpose. (And in any database, you could use a temporary table, but that is not a good solution.)
Note: Do not use natural join. It is a bug waiting to happen.
To expression your query, use either an ON or USING clause. For your query, it would be something like this:
Select c.*, ct.*
From Customers c Join
Transaction as CT
ON c.Customer_ID = CT.Customer_ID JOIN
(select t2.Customer_ID, count(*) as cnt
from Transaction t
group by t2.CustomerId
where cnt >= 2
) cct
ON cct.Customer_ID = cct.Customer_Id;
Based on your comment:
Grab all customers who have 2 or more transactions
Here's one option using exists:
select *
from customers c
where exists (
select 1
from transaction t
where c.customerid = t.customerid
having count(*) > 1
)

subquery that uses a value from the outer query in the where caluse

I wanna run a subquery that uses the value of the outer query in its where clause. Here's and example of what I wanna do:
SELECT * FROM `tbl1`
WHERE `tbl1`.`max_count` < (
SELECT COUNT(*) rc FROM `tbl2`
WHERE `tbl2`.`id` = `tbl1`.`id
)
There is tbl1 with a column named max_count, and there is tbl2 with rows referring to a row in tbl1(many-to-one relationship). What I wanna do is select rows in tbl1 where the number of rows in tbl2 referencing it is less than the max_count value of that row. But I'm pretty sure that what I wrote here, ain't gonna cut it. Any ideas?
Thanks a lot
try this -
SELECT * FROM `tbl1` t1
WHERE t1.`max_count` < (
SELECT COUNT(*) FROM `tbl2` t2
WHERE t2.`id` = t1.`id`
)
try using JOIN.
SELECT DISTINCT a.*
FROM tb1 a
INNER JOIN
(
SELECT id, COUNT(*) totalCount
FROM tbl2
GROUP BY id
) b ON a.ID = b.ID
WHERE a.max_count < b.totalCount
As an alternate solution, it's probably easier to just use a LEFT JOIN with HAVING than a subquery;
SELECT tbl1.*, COUNT(tbl2.id) current_count
FROM tbl1
LEFT JOIN tbl2
ON tbl1.id=tbl2.id
GROUP BY tbl1.id
HAVING COUNT(tbl2.id) < max_count
An SQLfiddle to test with.
Note that the GROUP BY in this case is a MySQL only thing, normally you'd need to GROUP BY every selected field in tbl1 even if tbl1.id is known to be unique per row.

Why IFNULL doesn't port from left join?

Basically I want a column to to return 0 if null. I'm using the ifnull inside a nested statement, when I run the nested statement by itself the column returns 0, but when I run the whole query I get NULL again. This is my code:
SELECT Text, Verbo, Objeto, mPosts FROM Posts
LEFT JOIN (SELECT ID, IFNULL(COUNT(*),0) AS mPosts FROM `Posts` WHERE Date >= DATE_ADD(CURDATE(), INTERVAL -30 DAY) GROUP BY `Verbo`,`Objeto`) AS B ON Posts.ID = B.ID
I could move the IFNULL to the main select statement, but I would rather not:
SELECT Text, Verbo, Objeto, IFNULL(mPosts,0) FROM Posts
LEFT JOIN (SELECT ID, COUNT(*) AS mPosts FROM `Posts` WHERE Date >= DATE_ADD(CURDATE(), INTERVAL -30 DAY) GROUP BY `Verbo`,`Objeto`) AS B ON Posts.ID = B.ID
Why I can't do it on the nested statement? Can it can be done any other way so that I don't have to use it on the main query?
If you are getting NULL for IFNULL(COUNT(*),0), it is because the LEFT JOIN is not matching with your ON clause of Posts.ID = B.ID, so all values in the right table will be NULL.
So yes, you will need to move IFNULL to the top-level SELECT clause.
You must have the IFNULL on the outer query.
The COUNT(*) in the inner query is not returning a NULL, the NULL is being created by the LEFT JOIN operation, when a row on the left side does not have a matching row from the row source on the right side.
This query is equivalent to yours:
SELECT a.Text
, a.Verbo
, a.Objeto
, c.mPosts
FROM `Posts` a
LEFT
JOIN ( SELECT b.ID
, COUNT(*) AS mPosts
FROM `Posts` b
WHERE b.Date >= DATE_ADD(CURDATE(), INTERVAL -30 DAY)
GROUP BY b.`Verbo`, b.`Objeto`
) c
ON c.ID = a.ID
The reformatted query makes it more obvious where the problem is.
Your inline view (the subquery) is performing a GROUP BY on two columns, and then returning the value of ID from some one row that is included in each of the count values.
(Other relational databases would throw a "non-aggregate in select list not in group by" type exception with this statement, where MySQL is more liberal, which is both a convenience and a curse.)
The result set returned by the query is quite odd. It's not clear what result set you want returned here.
The row from the "count" subquery is going to get matched with only one row included in each value of COUNT(). (Any time that COUNT(*) is greater than 1, there's going to be a row in the outer query that doesn't have a matching row from the inline view... that GROUP BY is collapsing all of the ID values of the included rows down to just one ID value of some one row that is included.
I hesitate to make any suggestions, because I'm not clear on what you want returned.
One thing you could do is to remove the predicate from the WHERE clause, and instead check that condition in the aggregate, something like this...
SELECT a.`Text`
, a.`Verbo`
, a.`Objeto`
, c.`mPosts`
FROM `Posts` a
LEFT
JOIN ( SELECT b.ID
, SUM(IF b.`Date` >= DATE_ADD(CURDATE(), INTERVAL -30 DAY)) AS `mPosts`
FROM `Posts` b
GROUP BY b.`Verbo`, b.`Objeto`
) c
ON c.ID = a.ID
That may reduce the number of NULL values, but it doesn't address the more fundamental issue of the LEFT JOIN generating NULL for any row on the left side that don't have a match from the right side.