I'm no MySQL specialist, so I need and advice for making a single query, joining another table and counting all joined rows as well rows with specific fields
This is my initial query:
SELECT e.id, e.event_fr, e.max_capacity, count(s.id) as subscriptions
FROM events e
INNER JOIN events_subscriptions s ON s.activity = e.id
GROUP BY e.id, e.event_fr
ORDER BY e.id ASC
Basically I'm trying to find out (count) number of subscriptions for given event.
But every subscription event also has a field called "waiting_list" which can be either 0 or 1. It tells me whether or not current subscribed person is on the waiting list or not.
I need to be able to count those as well to find out how many people are on the waiting list for the given event:
id: 3,
event_fr: Yoga & relaxation,
suscriptions: 14
waiting_list: 3
id: 4,
event_fr: Judo,
suscriptions: 10
waiting_list: 5
etc..
I understand a super outer join with subquery is missing..
Is it possible to be able to additionally count "waiting_list" on joined table? (e.g WHERE waiting_list = 1)
As I see it, you don't really need that additional count, because you already know what the event's max capacity is. So, you just have to subtract the subscriptions count from the e.max_capacity value, and that is the number of people currently on the waiting list.
Related
I'm new to SQL as for over 20 years I haven't touched a single code line, so it feels like starting over.
I have a database with two tables, one for Projects, and another one for the Milestones. What I'm trying to achieve is to have a query that will retrieve the latest Milestone logged for each project. That way I can build a report with one project line with the latest update only.
I've managed to build the query to retrieve 1 (One) Milestone Record for each project. However when I've logged more than one update for the same date, the query returns all of them. I've tried to utilize the rowid, but it didn't work.
Here my sample tables:
And the query I've tried to run that currently retrieves more than 1 record when milestone created the same date.
select PROJECT_DATA.PARTNER_NAME as PARTNER_NAME,
PROJECT_DATA.SOLUTION_STATUS as SOLUTION_STATUS,
PROJECT_DATA.STRATEGY_MANAGER as STRATEGY_MANAGER,
PROJECT_DATA.SOLUTION_TYPE as SOLUTION_TYPE,
PROJECT_DATA.INTEGRATION_METHOD as INTEGRATION_METHOD,
PROJECT_MILESTONE.MILESTONE as MILESTONE,
PROJECT_MILESTONE.COMPLETED_ON as COMPLETED_ON,
PROJECT_MILESTONE.NOTES as NOTES
from PROJECT_DATA JOIN PROJECT_MILESTONE PROJECT_MILESTONE ON PROJECT_DATA.ID=PROJECT_MILESTONE.PROJECT_ID
where PROJECT_MILESTONE.COMPLETED_ON = (Select MAX (PROJECT_MILESTONE.COMPLETED_ON)
FROM PROJECT_MILESTONE
WHERE PROJECT_DATA.ID=PROJECT_MILESTONE.PROJECT_ID)
Any help on how to limit the query result to just 1 (newest one) when logged in the same date, will be extremely helpful.
Assuming that Completed on has the time as well along with the date, all you need to do is select top 1 in the ORDER BY DESC
Something like
select top 1 PROJECT_DATA.PARTNER_NAME as PARTNER_NAME,
PROJECT_DATA.SOLUTION_STATUS as SOLUTION_STATUS,
PROJECT_DATA.STRATEGY_MANAGER as STRATEGY_MANAGER,
PROJECT_DATA.SOLUTION_TYPE as SOLUTION_TYPE,
PROJECT_DATA.INTEGRATION_METHOD as INTEGRATION_METHOD,
PROJECT_MILESTONE.MILESTONE as MILESTONE,
PROJECT_MILESTONE.COMPLETED_ON as COMPLETED_ON,
PROJECT_MILESTONE.NOTES as NOTES
from PROJECT_DATA JOIN PROJECT_MILESTONE PROJECT_MILESTONE ON
PROJECT_DATA.ID = PROJECT_MILESTONE.PROJECT_ID
order by COMPLETED_ON DESC
Also, the joining condition has to be specified after the "ON" in joins and then you can use where condition to filter out the data
I've never been able to get my head around INNER JOINs (or any other JOIN types for that matter) so I'm struggling to work out how to use it in my specific situation. In fact, I'm not even sure if it's what I need. I've looked at other examples and read tutorials but my brain just doesn't seem to work the way needed to truly get it (or it doesn't function at all).
Here's the scenario:
I have two tables -
phone_numbers - this table has a list of phone numbers that
belong to lots of different customers. A single customer can have
multiple numbers. For simplicity's sake, we'll say the fields are
'number_id', 'customer_id', 'phone_number'.
call_history - this table has a record of every single call that one of these
numbers in the first table could have had. There's a record for
every individual call going back years. Again, for simplicity,
we'll say the relevant fields are customer_id, phone_number,
call_start_time.
What I'm trying to accomplish is to find all of the numbers that belong to a particular customer_id in the phone numbers table and use that information to search through the call_history table and find the number of calls each phone number has received, and group that by the number of calls for each number, preferably also showing zeros where a number hasn't received any calls at all.
The reason the zero calls is important is because that's the data I'm interested in. Otherwise, I could just get all the information out of the call_history table. But what I'm trying to achieve is find the numbers with no activity.
All I've been able to accomplish is run one query to get all of the numbers belonging to one customer:
SELECT customer_id, phone_number FROM phone_numbers WHERE customer_id = Y;
Then run a second query to get all phone calls for that customer_id for a set duration:
SELECT customer_id, phone_number, COUNT(*) FROM call_history WHERE customer_id = Y and call_start_time >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY) GROUP BY phone_number;
I've then had to use the data returned from both queries and use a VLOOKUP function in Excel to match number of calls for each individual number from the second query to the list of all numbers from the first query, thus leaving blanks in my "all numbers" table and identifying those numbers that had no calls for that time period.
I'm hoping there's some way to do all of this with a single query and return a table of results, listing the zero number of calls with it and eliminate the whole manual Excel bit as it's not overly efficient and prone to human error.
Without at least a workable example from you, it's not easy to re-create your situation. Anyway, INNER JOIN might not return the result as how you expected. In my short time with MySQL, I mainly use 2 types of JOIN; one is already mentioned and the other is LEFT JOIN. From what I can understand in your question, what you want to achieve can be done by using LEFT JOIN instead of INNER JOIN. I may not be the best person to explain this to you but this is how I understand it:
INNER JOIN - only return anything that match in ON clause between two (or more) tables.
LEFT JOIN - will return everything from the table on the left side of the join and return NULL if ON get no match in the table on the right side of the join .. unless you specify some WHERE condition from something on the right table.
Now, here is my query suggestion and hopefully it'll be useful for you:
SELECT A.customer_id, A.phone_number,
SUM(CASE WHEN call_start_time >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY)
THEN 1 ELSE 0 END) AS Total
FROM phone_numbers A
LEFT JOIN call_history B
ON A.customer_id=B.customer_id
GROUP BY A.customer_id,A.phone_number;
What I did here is I LEFT JOIN phone_numbers table with call_history on customer_id and I re-position the WHERE call_start_time >= .. condition into a CASE expression in the SELECT since putting it at WHERE will turn this into a normal join or inner join instead.
Here is an example fiddle : https://www.db-fiddle.com/f/hriFWqVy5RGbnsdj8i3aVG/1
For Inner join You should have to do like this way..
SELECT customer_id,phone_number FROM phone_numbers as pn,call_history as ch where pn.customer_id = ch.customer_id and call_start_time >= DATE_SUB(SYSDATE(), INTERVAL 30 DAY) GROUP BY phone_number;
Just add table name whatever you want to join and add condition
I am in the process of creating an attendance system and have created 3 different reports to generate based on the content of 3 different MySQL tables: members, attendance, and absence.
I am having an issue though. One of the reports is working since I have the correct statement. However, I cannot get the other two to work, so I need some help on how to figure out the best SQL statement for these reports.
The first report I need has to look like this:
This report shows how many people in each precinct showed up to the event and how many excused absences are in that precinct. For this report, I will also need a "Totals" line at the very bottom to count the total number of attendees, excused absences and totals from each precinct (like this):
The second report is similar to the report that is already completed. The difference is instead of the member's email and phone address, I need to see if they were marked present and if they had an excused absence. I cannot show the report since there is real data about real people, however I can show you the SQL statement that the completed report is using:
SELECT
precinct, name, residential_address, member_email, member_phone, present, alternate
FROM
attendance INNER JOIN members ON members.id = attendance.member_id
WHERE
present = 1
ORDER BY
members.precinct
I've tried SQL COUNT statements and various JOIN queries to try and make the queries work, but nothing is working at all. What is the correct query and why?
UPDATE
Here is my table structure of the 3 tables involved in the report generation. Note that each table (other than Members) shares the Member ID column:
Members Table:
Attendance Table:
Absence Table:
This is untested against actual data, but should be close to what you're looking for.
Your first report (http://sqlfiddle.com/#!9/191d8d/1) should be:
SELECT
m.precinct as 'precinct',
COUNT(at.member_id) as 'delagates_present',
COUNT(ab.member_id) as 'delegates_absent',
COUNT(at.member_id) + COUNT(ab.member_id) as 'total'
FROM
members m
LEFT JOIN attendance at ON at.member_id = m.id
LEFT JOIN absence ab ON ab.member_id = m.id
GROUP BY
m.precinct
WITH ROLLUP;
This selects all members, groups them by precinct, counts how many were present or absent, and then adds those together for the total column. Additionally, WITH ROLLUP will give you the sums of the columns (https://dev.mysql.com/doc/refman/8.0/en/group-by-modifiers.html) as the last row.
Then your second report (http://sqlfiddle.com/#!9/191d8d/2) should be:
SELECT
precinct,
name,
residential_address,
IF(at.member_id IS NULL, 0, 1) as 'present',
IF(ab.member_id IS NULL, 0, 1) as 'absent',
alternate
FROM
members m
LEFT JOIN attendance at ON at.member_id = m.id
LEFT JOIN absence ab ON ab.member_id = m.id
ORDER BY
m.precinct,
m.id;
which selects all members and does a LEFT JOIN on the other 2 tables. Then we can use a condition in the SELECT to determine if they were present or absent. There are a number of ways that data could be represented and returned, but I've opted for a simple 1 or 0 in both of those columns.
I got two tables that contain date and time stamps and trying to extract records by the latest date in both.
Table 1 (sessions):
id---login_date------------ip
01---2014-01-02 23:58:40---127.0.0.1
03---2014-01-01 13:20:16---127.0.0.1
01---2014-01-01 17:06:15---127.0.0.1
02---2013-12-30 14:34:39---127.0.0.1
*also multiple other non-date columns which are not playing part in this solution
Table 2 (reminders):
id---last_reminder---------next_reminder
03---2013-12-29 22:50:18---2014-01-07 22:50:18
02---2014-01-01 15:15:15---2014-01-09 15:15:15
02---2013-11-16 08:54:23---2013-11-23 08:54:23
Now this is the way I get all the latest logins from the first table for each user ID:
SELECT a.id, a.login_date
FROM sessions a
WHERE a.login_date = (
SELECT max(login_date) as login_date
FROM sessions
WHERE id = a.id
LIMIT 1
)
GROUP BY a.id
What I would like to get is not only the last login date for each user ID, but also the last sent reminder (if any). As this involves selecting two max dates I never get correct results.
Desired Result:
id---login_date------------last_reminder---------next_reminder------
01---2014-01-02 23:58:40---NULL------------------NULL---------------
02---2013-12-30 14:34:39---2014-01-01 15:15:15---2014-01-09 15:15:15
03---2014-01-01 13:20:16---2013-12-29 22:50:18---2014-01-07 22:50:18
Would anybody please help me out with this.
Thanks,
Simon
////////////////////////UPDATED 2014-01-04 WITH EXTRA COLUMNS////////////////////////////
Based on the request the above table structure was updated to contain extra fields, required to produce correct query results.
*note that next_reminder field will always have a value as it's calculated based on the last reminder value. The query will eventually check whether the next reminder is within certain timeframe too.
P.S. StackOverflow is full of very good answers when only one table contains the date and time stamp (from which I have built what I have got so far), however I could not locate any similar examples that would involve joining two tables and selecting max dates from each.
if you have only two columns per table, you can directly join it and use MAX() to get the latest record for each ID.
SELECT a.id,
MAX(login_date) latest_login_date,
MAX(last_reminder) latest_reminder
FROM sessions a
LEFT JOIN reminders b
ON a.id = b.id
GROUP BY a.id
SQLFiddle Demo
I have two DB tables, one that store events and the second that stores any associated comments for that event.
DB Tables:
events: id, owner_id, timestamp
comments: cmt_id, parent_id(events id), cmt_time
I'm trying to get the last 5 comments for each event based on a specific owner_id.
This is how I'm joining my tables:
SELECT * FROM `events`
LEFT JOIN comments ON comments.parent_id=events.id
WHERE owner_id=X
ORDER BY timestamp DESC LIMIT 0,5
Any idea how I can get the number of comments based on the event_id?
Your question is about the number of comments for each event (at least as I interpret it). For this, you want to use a group by:
SELECT e.event_id, COUNT(c.parent_id) as NumComments
FROM events e left JOIN
comments c
ON c.parent_id=e.id
WHERE e.owner_id = X
group by e.event_id;
As for the query in your question. It does not do what you want it to do ("I'm trying to get the last 5 comments for each event based on a specific owner_id."). Instead, it is getting the last five comments for a given user. Period.
You can do the table join at then use the COUNT() function to count how many comments are associated with a given event_id
http://www.w3schools.com/sql/sql_func_count.asp
I would give an example but I'm not entirely sure what you would like your end dataset to look like. COUNT(col) will count the number of rows associated with the query result