I'm trying to return a list of users, ordered by a field (pt_seen) on the users most recent row.
Does that make sense?
So far I have:
SELECT u.users_id,
u.username,
ed.date
FROM users u
LEFT JOIN exercises_done ed
ON ed.user_id = u.users_id
WHERE u.pt_id = 1
GROUP BY u.users_id
Which obviously just returns the users grouped.
The tables look like this:
users:
users_id | pt_id | username
1 | 1 | billy
2 | 1 | bob
3 | 1 | sue
exercises_done:
exercises_done_id | user_id | pt_id | exercises_done_date | pt_seen
1 | 1 | 1 | 2018-01-01 | 0
2 | 1 | 1 | 2018-01-02 | 0
3 | 1 | 1 | 2018-01-03 | 1
4 | 2 | 1 | 2018-01-05 | 1
5 | 3 | 1 | 2018-01-04 | 0
and I'm trying to get results like this:
users_id | username | exercises_done_date | pt_seen
1 | billy | 2018-01-02 | 0
3 | sue | 2018-01-04 | 0
2 | bob | 2018-01-05 | 1
The aim is that I show users at the top of the list who have a pt_seen value of 0, then ordered by exercises_done_date.
Any help would be great,
You can select the most recent exercise in the where clause rather than using aggregation:
SELECT u.users_id, u.username, ed.*
FROM users u LEFT JOIN
exercises_done ed
ON ed.user_id = u.users_id
WHERE ed.exercises_done_date = (SELECT MAX(ed2.exercises_done_date)
FROM exercises_done ed2
WHERE ed2.user_id = ed.user_id
) AND
u.pt_id = 1
ORDER BY u.pt_seen, exercises_done_date DESC;
You can add an ORDER BY clause after your GROUP BY.
SELECT u.users_id, u.username, ed.date FROM
users u
LEFT JOIN exercises_done ed ON ed.user_id = u.users_id
WHERE
u.pt_id = 1
GROUP BY
u.users_id
ORDER BY
pt_seen, exercises_done_date
Related
I have three tables, two of which are relevant for this question. Users, Things, User_to_thing
Users
ID | Name | Active
-------------------
1 | Joe | 1
2 | Jack | 1
3 | Tom | 1
4 | Harry | 0
5 | Stan | 1
6 | Bob | 1
User_to_thing
Thing ID | User ID | Status
---------------------------
3 | 1 | 1
3 | 2 | 2
3 | 5 | 1
4 | 1 | 3
4 | 2 | 2
I'm trying to create a query where I can select all the active users in the users table and have a column where I can see the status for "thing 3" from the User_to_thing table while also sorting results so that the nulls come at the end. So the result would be something like:
User ID | Status
----------------
1 | 1
2 | 2
5 | 1
3 | NULL
6 | NULL
What I have so far for a query is the following:
SELECT u1.id, u1.name, user_to_thing.status
FROM users u1
LEFT JOIN user_to_thing ON u1.id = user_to_thing.user_id
WHERE u1.active = 1
OR user_to_thing.event_id = 62
ORDER BY (CASE WHEN user_to_thing.status = 1 THEN 1
WHEN user_to_thing.status = 2 THEN 2
ELSE 3 END)
What I'm getting as a result is the following:
User ID | Status | Thing ID
---------------------------
1 | 1 | 3
1 | 3 | 4
2 | 2 | 3
2 | 2 | 4
5 | 1 | 3
3 | NULL | NULL
6 | NULL | NULL
I'm not sure how to limit it to just thing #3 while also getting a list of all active users. Any guidance would be appreciated.
It looks like the following should work for you, grouping to remove duplicates and ordering based on null
select u.Id as UserId, t.status
from users u
left join User_to_thing t on t.UserID = u.id
where u.active = 1
group by u.Id, t.Status
order by case when status is null then 1 else 0 end, u.Id
Based on your revised data, you can amend slightly
select u.Id UserId, Min(t.status) Status
from users u
left join User_to_thing t on t.UserID=u.id
where u.active=1
group by u.Id
order by case when Min(t.status) is null then 1 else 0 end, u.Id
NOTE: This is not the same as this question, as I need to get data from two other records, not two fields from one one other record!
MySQL newb. I have two tables, and I want to get data from both of them so I have the following:
wp_bowling_fixtures
fixture_id | fixture_date | home_team_id | away_team_id
-----------+--------------+--------------+-------------
1 | 2017-12-12 | 1 | 2
2 | 2017-12-12 | 3 | 4
3 | 2017-12-12 | 5 | 6
4 | 2017-12-12 | 7 | 8
5 | 2017-12-12 | 9 | 10
wp_bowling_teams
team_id | name | division | archived
--------+--------+----------+---------
1 | Team A | 1 | 0
2 | Team B | 1 | 0
3 | Team C | 2 | 1
4 | Team D | 2 | 0
5 | Team E | 3 | 0
6 | Team F | 3 | 0
7 | Team G | 4 | 0
8 | Team H | 4 | 1
9 | Team I | 4 | 0
10 | Team J | 4 | 0
The result I want a SELECT query to produce:
fixture_id | fixture_date | home_team_id | home_team_name | home_team_archived | home_team_division | away_team_id | away_team_name | away_team_archived | away_team_division
-----------+--------------+--------------+----------------+--------------------+--------------------+--------------+----------------+--------------------+-------------------
1 | 2017-12-12 | 1 | Team A | 0 | 1 | 2 | Team B | 0 | 1
I also want it ordered by fixture_date DESC, home_team_division ASC, home_team_name ASC.
Hope that makes sense.
TIA,
Nick.
SELECT f.fixture_id, f.fixture_date, h.team_id as home_team_id, h.name as home_team_name, h.archived as home_team_archived, h.division as home_team_division, a.team_id as away_team_id, a.name as away_team_name, a.archived as away_team_archived, a.division as away_team_division FROM wp_bowling_fixtures f, wp_bowling_teams h, wp_bowling_teams a where f.home_team_id = h.team_id and f.away_team_id = a.team_id order by f.fixture_date desc, h.division asc, h.name asc;
Works.
Nothing in sql stops you joining a table twice but if you do so you must alias them .
You're looking for a query that uses
fixtures f
JOIN teams h ON f.home_team_id = h.team_id
JOIN teams a ON f.away_team_id = a.team_id
I gave the teams h (for home) and a (for away) aliases so I could tell them apart. Give it a go at filling it out
select x.fixture_id, x.fixture_date, x.home_team_id, x.home_team_name, x.home_team_archived, x.home_team_division,
y.away_team_id, y.away_team_name, y.away_team_archived, y.away_team_division from
(select a.fixture_id, a.fixture_date, a.home_team_id, b.name home_team_name, b.archived home_team_archived, b.division home_team_division
from wp_bowling_fixtures a inner join wp_bowling_teams b on A.home_team_id = B.team_id) x
inner join
(select a.fixture_id, a.fixture_date, a.away_team_id, b.name away_team_name, b.archived away_team_archived, b.division away_team_division
from wp_bowling_fixtures a inner join wp_bowling_teams b on A.away_team_id = B.team_id) y on x.fixture_id = y.fixture_id
order by x.fixture_date desc, home_team_division asc, home_team_name asc;`enter code here`
So i have three tables:
Users
+-------+-----+----+
| id | val1|val2|
+-------+-----+----+
| 1 | 1 |3 |
| 2 | 2 |5 |
| 3 | 4 |7 |
+-------+-----+----+
UsersData
+----+--------------+------------+-----|
| id | users_id | created_at | gold|
+----+--------------+------------+-----|
| 9 | 1 |121454561212| 14 |
| 10| 1 |131454561212| 2 |
| 11| 2 |111454561212| 99 |
+----+--------------+------------+-----+
Extra
+----+------------+-----|
| id | users_id | val4|
+----+------------+-----|
| 1 | 1 | 5 |
| 2 | 1 | 6 |
| 3 | 1 | 7 |
+----+------------+-----+
So what i wish to achieve(in a single query) is to get a single row result for user with id = 1, that holds:
everything from Users Table
gold value of the most recent entry for that user (users_id = 1, created_at = MAX)
biggest val4 from the Extra table, where users_id = 1
So the result row would look like this:
+-------+-----+----+-----+----+
| id | val1|val2|gold |val4|
+-------+-----+----+-----+----|
| 1 | 1 |3 | 2 | 7 |
------------------------------+
I can get The first part done with
SELECT Users.id, Users.val1, Users.val2, UsersData.gold
FROM UsersData
LEFT JOIN Users ON UsersData.users_id = Users.id
WHERE Users.id = 1
ORDER BY UsersData.created_at DESC
LIMIT 1
and the second part with
SELECT MAX(Distances.distance) AS maxdistance FROM Distances WHERE Distances.users_id = 1
But i can't combine them no matter how i try... I would really like to have this done in single query, obviously i can do it with multiple - but i believe it is just my lack of mysql skills that is the issue here.
Thanks!
Just use subquery:
SELECT Users.id, Users.val1, Users.val2, UsersData.gold,
(SELECT MAX(Distances.distance) FROM Distances WHERE Distances.users_id = Users.id) AS maxdistance
FROM UsersData
RIGHT JOIN Users ON UsersData.users_id = Users.id
WHERE Users.id = 1
ORDER BY UsersData.created_at DESC
LIMIT 1
This is subquery connected by Users.id:
SELECT MAX(Distances.distance) FROM Distances WHERE Distances.users_id = Users.id) AS maxdistance
I would use subqueries like this:
select u.*,
(select ud.gold
from userdata ud
where ud.users_id = u.id
order by ud.created_at desc
limit 1
) as most_recent_gold,
(select max(e.val4)
from extra e
where e.users_id = u.id
) as max_val4
from users u
where u.id = 1 ;
Currently, I'm using this nice query:
select
users.name,
sum(race_results.winnings) as total_winnings,
count(CASE WHEN race_results.place=1 THEN 1 ELSE 0 END) AS times_won_first_place
from users
inner join race_results
where race_results.userid = users.id and race_results.place = 1
group by users.id
order by total_winnings desc
to get this
************************************************
| name | total_winnings | times_won_first_place |
| Bob | 4000 | 4 |
| John | 1000 | 1 |
************************************************
the race_results table looks like this
*******************************************
| id | raceid | userid | place | winnings |
| 1 | 1 | 1 | 1 | 1000 |
| 2 | 1 | 2 | 5 | 50 |
| 3 | 1 | 3 | 6 | 50 |
| 4 | 2 | 1 | 1 | 1000 |
| 5 | 2 | 2 | 3 | 250 |
*******************************************
I would like to include four three more columns for something like this
***************************************************************************
| name | total_winnings | total_races | 1st_place | 2nd_place | 3rd_place |
| Bob | 4000 | 5 | 4 | 0 | 0 |
| John | 1000 | 5 | 1 | 1 | 1 |
***************************************************************************
If I were to do separate queries for the new columns, I'd use
select count(raceid) from race_results where userid = 1
select count(raceid) from race_results where userid = 1 and place = 1
select count(raceid) from race_results where userid = 1 and place = 2
select count(raceid) from race_results where userid = 1 and place = 3
to do separate queries would be easy but with the existing query I had to use CASE just to get the count of times a user won 1st place. (using
count(CASE WHEN race_results.place=2 THEN 1 ELSE 0 END)
returns the same results).
How would I nest these or join them into my existing query to get what I want?
You can do it this way:
select
users.name,
sum(race_results.winnings) as total_winnings,
count(*) AS total_races,
sum(race_results.place = 1) AS times_won_first_place ,
sum(race_results.place = 2) AS times_won_second_place,
sum(race_results.place = 3) AS times_won_third_place
from users
inner join race_results
where race_results.userid = users.id
group by users.id
order by total_winnings desc;
With ANSI standard SQL you could use case expressions inside the sum function but since MySQL (and some other databases) evaluate boolean expressions to 1 for true you can replace the case expression with the just the condition to evaluate and then just sum them.
So instead of CASE WHEN race_results.place=1 THEN 1 ELSE 0 END you can do sum(race_results.place=1) and save some space and typing :)
See this SQL Fiddle for an example.
I have a table which holds a customer and another table which holds results from that customer.
One customer can have many results.
I want to be able to firsly select only the customers which have more than one entry in CustResults, and then from those, I want all the records except the first one...
I have this so far, which retrieves the customers with more than one result, but I don't know how to then ingore then first result.
SELECT * FROM CustResults cp
JOIN Customer c ON c.CustomerID = cp.CustomerID
WHERE
(SELECT count(CustomerID) as cpid
FROM CustResults WHERE CustomerID = cp.CustomerID GROUP BY CxID) > 1
i.e.
Rita: RESULT 1
Sue: RESULT 1, Result 2, Result 3, Result 4
Bob: RESULT 1, Result 2, Result 3
I only want Sue and Bob, as Rita only has one result, and from Sue and Bob, I only want to look at results 2,3,4
Any ideas?
Thanks
ADDED MORE INFO:
Here is my exact query:
SELECT count(cp.CxID) as intSmokers
FROM CustPrimarySmoking cp
JOIN Customer c ON cp.CxID = c.CustomerID
WHERE (SELECT count(CustPrimarySmokingID) as cqpid FROM CustPrimarySmoking WHERE CxID = cp.CxID GROUP BY CxID) > 1
Obviously, I can just use LIMIT 1, 99999, because the query is only returning one value (the count).
I want the count to be using the customers with more than one record in CustPrimarySmoking, but ignoring the first entry.
Any futher ideas?
Stupid and not-so flexible (however, it should works all most of the time) ...
LIMIT 1, 999999999;
^ to ensure all rows are returned
Have you tried to add "OFFSET 1" at the end of the query?
If all you are after is the count and not the actual records then you just need to subtract the number of customers from the count you already have (as you have already ascertained that each as at least one record) i.e.
SELECT count(cp.CxID)-count(DISTINCT cp.CxID) as intSmokers
FROM CustPrimarySmoking cp
JOIN Customer c ON cp.CxID = c.CustomerID
WHERE (
SELECT count(CustPrimarySmokingID) as cqpid
FROM CustPrimarySmoking WHERE CxID = cp.CxID
GROUP BY CxID
) > 1
If however you are after the actual rows, how about this:
SELECT * FROM Customer;
+------------+------+
| CustomerID | name |
+------------+------+
| 1 | Rita |
| 2 | Sue |
| 3 | Bob |
| 4 | Jack |
+------------+------+
SELECT * FROM CustPrimarySmoking;
+----------------------+------+-------------------+
| CustPrimarySmokingID | CxID | result |
+----------------------+------+-------------------+
| 1 | 1 | Result 1 for Rita |
| 2 | 2 | Result 1 for Sue |
| 3 | 2 | Result 2 for Sue |
| 4 | 2 | Result 3 for Sue |
| 5 | 2 | Result 4 for Sue |
| 6 | 3 | Result 1 for Bob |
| 7 | 3 | Result 2 for Bob |
| 8 | 3 | Result 3 for Bob |
+----------------------+------+-------------------+
SELECT * FROM CustPrimarySmoking cp
JOIN Customer c ON cp.CxID = c.CustomerID
WHERE CustPrimarySmokingID <> (
SELECT CustPrimarySmokingID
FROM CustPrimarySmoking
WHERE CxID = cp.CxID ORDER BY CustPrimarySmokingID LIMIT 1
);
+----------------------+------+------------------+------------+------+
| CustPrimarySmokingID | CxID | result | CustomerID | name |
+----------------------+------+------------------+------------+------+
| 3 | 2 | Result 2 for Sue | 2 | Sue |
| 4 | 2 | Result 3 for Sue | 2 | Sue |
| 5 | 2 | Result 4 for Sue | 2 | Sue |
| 7 | 3 | Result 2 for Bob | 3 | Bob |
| 8 | 3 | Result 3 for Bob | 3 | Bob |
+----------------------+------+------------------+------------+------+