I am trying to develop a ranking table for a sort of questionnaire.
Each day a question is asked at 16h (4:00 pm), which can be answered by 17:59:59 the following day. The table has to show the position of the participants taking into account the correct answers is the time.
My table will be of the sort:
+-------+---------+---------------------+
|userid | correct | timestamp |
+-------+---------+---------------------+
| 2 | 1 | 2018-02-07 16:00:01 |
| 1 | 1 | 2018-02-07 16:02:00 |
| 3 | 1 | 2018-02-07 17:00:00 |
| 1 | 0 | 2018-02-08 16:00:02 |
| 3 | 1 | 2018-02-08 16:00:05 |
| 2 | 0 | 2018-02-08 16:01:00 |
+-------+---------+---------------------+
For now I started with this query:
SELECT `userid`, `correct `, `timestamp`,
count(correct) as count
FROM `results`
WHERE correct = 1
GROUP BY `userid `
ORDER BY count DESC, timestamp DESC
But I have already realized that this is not what I intend because the ranking has to be cumulative but taking into account the several days.
Does anyone have an idea how I can do this?
A user from Stackoverflow Portugal advised this code but it is not working either.
SELECT userid, SUM(correct),
SUM(TIMESTAMPDIFF(HOUR,(timestamp,CAST(CONCAT_WS(' ',date(timestamp), '17:59:59') as DATETIME)))) time
FROM results
GROUP BY userid
ORDER BY correct DESC, time
Don’t deal with this datetime (16h), this may be changed and you will be lost on your query.
Instead, you should count by userid and questionnaire_id. To do so:
add new table questionnaire [id, title] (you can add extra column
later : created_time, end_time, …)
edit your record table by adding the questionnaire id as FK : [userid, questionnaireid, correct, timestamp]
then count normally: Correct answer by user, by questionnaire
SELECT userid, questionnaireid ,
sum(correct) as total
FROM results r
INNER JOIN questionnaire q
ON r.questionnaireid = q.id
WHERE correct = 1
GROUP BY userid, questionnaireid
ORDER BY total DESC, id ASC
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
Trying to retrieve records by first summing their time_spent, then using max to retrieve the largest record by time. which seems to be working.
I need to now check if on the chance that the sum of time_spent are the same value for users (a tie, like in the example below, both users have time_spent as 10 so it should then select the user that has the latest post), if they are then I need to only get the user_id that was posted last (newer) using the created_at column. I just don't know what to use to do that check, is it a CASE, or IF Function? and if so where would it go in my query?
Here is a sql fiddle link: http://sqlfiddle.com/#!9/f24985/2
Table1 layout
+----+---------+-----------+---------+------------+------------+
| id | user_id | member_id | item_id | time_spent | created_at |
+----+---------+-----------+---------+------------+------------+
| 1 | 1 | 1 | 1 | 5 | 2019-06-01 |
| 2 | 2 | 1 | 1 | 1 | 2019-06-07 |
| 3 | 2 | 1 | 1 | 5 | 2019-06-08 |
| 4 | 2 | 1 | 2 | 4 | 2019-06-01 |
| 5 | 1 | 1 | 2 | 5 | 2019-06-07 |
+----+---------+-----------+---------+------------+------------+
Current SQL:
SELECT
MAX(attribute_time.sum_time), attribute_time.user_id
FROM (
SELECT
SUM(time_spent) AS sum_time, user_id
FROM
table1
WHERE
member_id = 1
AND item_id IN (1, 2)
AND (created_at BETWEEN '2019-06-1' AND '2019-06-30')
GROUP BY
user_id
ORDER BY
sum_time desc
) AS attribute_time;
In this example, both users have a total of 10 for time, currently returns the first record of the 2 and not based on the created_at date, which in this case, should be user 2.
Expected
+---------+
| user_id |
+---------+
| 2 |
+---------+
This is what you are looking for. http://sqlfiddle.com/#!9/a5306c/4/0
The MAX clause is problematic for sub-queries involving quantities unless you use some repetitive and verbose queries (DRY!), as seen in answer here: MySQL: Select MAX() from sub-query with COUNT() - it seems to decouple the rows, so you get the highest (max) sum_time with the wrong id (I thought I was seeing things, seemed so simple)
I used LIMIT to get around it. Sorting descending (the highest on top), and then LIMITing the result to 1 achieves the same thing as "Max".
Also - Im not sure if in event of a tie in max time you wanted to pick the earliest or latest record, but this picks the latest. I use MAX to pick the last day/time for each user, and orderby sum_of_time, then by date. If you want the opposite, sub MIN for MAX and/or DESC for ASC in the order-by. Regards! Thx for the exercise.
SELECT
SUM(time_spent) AS sum_time, user_id, MAX(created_at)
FROM
Table1
WHERE
member_id = 1
AND item_id IN (1, 2)
AND (created_at BETWEEN '2019-06-1' AND '2019-06-30')
GROUP BY
user_id
ORDER BY
sum_time DESC, created_at DESC
LIMIT 1
Try to use this it will give you user id 2
SELECT
MAX(attribute_time.sum_time), attribute_time.user_id
FROM (
SELECT
SUM(time_spent) AS sum_time, user_id
FROM
table1
WHERE
member_id = 1
AND item_id IN (1, 2)
AND (created_at BETWEEN '2019-06-1' AND '2019-06-30')
GROUP BY
user_id
ORDER BY
sum_time,user_id desc
) AS attribute_time;
I'm finishing up a system for buying event tickets, and I need to be able to check if there are still tickets available.
I have a table (tbl_rel_order_status) that makes a relation between orders and new statuses received from a payment gateway (like, say, PayPal). Every new transaction generates a new entry.
Structure and example for tbl_rel_order_status (tbl_order_id and tbl_status_order_id are FKs)
| id | tbl_order_id | tbl_status_order_id | datetime |
| 1 | 1 | 1 | 2016-08-01 18:20:00 |
| 2 | 1 | 3 | 2016-08-01 18:20:00 |
Structure and example for tbl_order (tbl_ticket_id, tbl_client_id and tbl_payment_method_id are FKs)
| id | tbl_ticket_id | tbl_client_id | tbl_payment_method_id | qnty |
| 1 | 1 | 1 | 1 | 40 |
| 2 | 1 | 2 | 1 | 3 |
I have a few "cancellation statuses" (namely: 6,7,8,11,13,15), which all mean that for some reason that amount of tickets can be made available again for other clients.
Here's the thing: I'm working on a query to retrieve the quantities of tickets which have as latest status any of the mentioned above. If not, the query should skip to the next ticket (that's where I'm stuck).
SELECT tbl_order.qnty
FROM (SELECT tbl_order_id,tbl_status_order_id
FROM tbl_rel_order_status
WHERE tbl_status_order_id IN ('6','7','8','11','13','15')
ORDER BY id DESC) inside
INNER JOIN tbl_order on tbl_order.id = inside.tbl_order_id
GROUP BY tbl_status_order_id
With that query I can only get the ones that DO have any of these, but not for the latest (or newest) DB entry.
SQL Fiddle
Any clues?
You can get the latest status using a query like this:
select o.*,
(select ros.tbl_status_order_id
from tbl_rel_order_status ros
where ros.tbl_order_id = o.id
order by ros.datetime desc
limit 1
) as last_status
from tbl_order o;
From this, I think you want:
select o.*,
(select ros.tbl_status_order_id
from tbl_rel_order_status ros
where ros.tbl_order_id = o.id
order by ros.datetime desc
limit 1
) as last_status
from tbl_order o
having last_status in ('6', '7', '8', '11', '13', '15');
Note: I'm not sure if I gave this question the most leading title since I'm not sure on the correct approach towards this, but I couldn't find other examples anywhere since it's quite a specific query.
So, I have a table "votes", which is filled with votes created by users (uniquely identified as a number in the user_id column) which correspond to relevent posts in another table (vote records "upvote" each relevent post within the user interface).
I intend to sort these votes (by datetime) in order of latest vote created for each post (post_id column), and as such, avoiding duplicate returned values of each post_id.
I input the following query:
SELECT id, user_id, post_id, created, MAX(created)
FROM votes
GROUP BY post_id, user_id
ORDER BY max(created) DESC
And get returned:
Table: votes
id | user_id | post_id | created | MAX(created)
----+-----------+-----------+-----------------------+--------------------
115 | 1 | 42 | 2014-07-03 23:08:31 | 2016-03-07 12:08:31
----+-----------+-----------+-----------------------+--------------------
237 | 2 | 101 | 2014-02-13 23:05:14 | 2016-03-05 23:05:14
----+-----------+-----------+-----------------------+--------------------
431 | 7 | 944 | 2014-10-22 22:58:37 | 2016-03-03 19:58:37
----+-----------+-----------+-----------------------+--------------------
255 | 15 | 101 | 2014-02-15 14:02:01 | 2016-02-01 23:05:14
----+-----------+-----------+-----------------------+--------------------
... | ... | ... | ... | ...
As you can see, there is a duplicate of the post_id "101". The result of this query seems to sort by maximum created time for each user_id, showing duplicated post_id's, e.g. there are two post_id column rows of "101", when I would only like to diplay the only post_id column value of "101" which has the maximum created time (MAX(created)).
The post_id and user_id columns seemingly must be grouped together, else if I just group by post_id I'm unable to sort by MAX(created) since it won't return the max(created) for each post_id.
How do I remove these duplicated post_id values that don't return the maximum created time?
What I'm after:
Table: votes
id | user_id | post_id | created | MAX(created)
----+-----------+-----------+-----------------------+--------------------
115 | 1 | 42 | 2014-07-03 23:08:31 | 2016-03-07 12:08:31
----+-----------+-----------+-----------------------+--------------------
237 | 2 | 101 | 2014-02-13 23:05:14 | 2016-03-05 23:05:14
----+-----------+-----------+-----------------------+--------------------
431 | 7 | 944 | 2014-10-22 22:58:37 | 2016-03-03 19:58:37
----+-----------+-----------+-----------------------+--------------------
... | ... | ... | ... | ...
Assuming you only want the last vote for each post:
SELECT v.*
FROM posts p
JOIN votes v
ON v.id =
(
SELECT id
FROM votes vi
WHERE post_id = p.id
ORDER BY
created DESC
LIMIT 1
)
If you are looking for getting last user_id whom edited post_id, try group by post_id and ordering by time desc (or id if it is auto increment).
SELECT tbl.* , GROUP_CONCAT('(',tbl.user_id,',',tbl.created,')') as myhistory FROM
(SELECT id, user_id, post_id, created, MAX(created)
FROM votes
ORDER BY max(created) DESC
) as tbl
GROUP BY tbl.post_id
If you need history for (user_id,time) you can use group_concat function as mentioned in code for myhistory column.
SELECT maintable.*
FROM TABLE_NAME maintable
LEFT OUTER JOIN TABLE_NAME temporarytable
ON maintable.GROUPING_BY_COLUMN = temporarytable.GROUPING_BY_COLUMN
AND maintable.COLUMN_WHERE_THE_MAXIMUM_IS_NEEDED < temporarytable.COLUMN_WHERE_THE_MAXIMUM_IS_NEEDED
WHERE temporarytable.COLUMN_WHERE_THE_MAXIMUM_IS_NEEDED IS NULL
ORDER BY PRIMARY_KEY_COLUMN DESC
LIMIT 50;
An alternative way to get the maximum value from a group. This query does not require aggregation, as is the case with “GROUP BY”.
In addition, when grouping using “GROUP BY”, each of the groups is sorted by primary key, which also takes a lot of time.
My query compares the values of one table with another. Until he can find nothing more. If nothing else is found, then this is the maximum.
This query can help you save time getting the maximum value from the group.
I want to ask about SQL in mysql. Im stack over 1 hour :(
I have sql :
SELECT TZL.IsMissed, COUNT(TZL.ChatID) as Amount FROM tblLog TZL group by TZL.IsMissed
And the result :
| IsMissed | Amount |
| 0 | 100 |
| 1 | 500 |
I want add one more column after Amount column, let say the name of new column is SumAmount. i want SumAmount value is SUM of the Amount Column.
| IsMissed | Amount | SumAmount |
| 0 | 100 | 600 |
| 1 | 500 | 600 |
I already try sql like below :
SELECT
tbl.*,SUM(tbl.Amount) as SumAmount
FROM
(
SELECT
TZL.IsMissed,
COUNT(TZL.ChatID) AS Amount
FROM
tblLog TZL
GROUP BY
TZL.IsMissed
) tbl
GROUP BY
tbl.IsMissed
WITH ROLLUP
But with ROLLUP the result is add a new one row, not column. Anyone can teach me for this ?
Thanks for answer
There are several ways to approach this. I would calculate the value in the from clause:
SELECT TZL.IsMissed, COUNT(TZL.ChatID) as Amount, tt.SumAmount
FROM tblLog TZL CROSS JOIN
(SELECT COUNT(*) as SumAmount FROM tblLog) tt
GROUP BY TZL.IsMissed, tt.SumAmount;
I am trying to construct a highscore table from entries in a table with the layout
id(int) | username(varchar) | score(int) | modified (timestamp)
selecting the highest scores per day for each user is working well using the following:
SELECT id, username, MAX( score ) AS hiscore
FROM entries WHERE DATE( modified ) = CURDATE( )
Where I am stuck is that in some cases plays may achieve the same score multiple times in the same day, in which case I need to make sure that it is always the earliest one that is selected because 2 scores match will be the first to have reached that score who wins.
if my table contains the following:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
3 | userA | 22 | 2014-01-22 16:13:22
4 | userB | 15 | 2014-01-22 18:49:01
The returned winning table in this case should be:
id | username | score | modified
________|___________________|____________|_____________________
1 | userA | 22 | 2014-01-22 08:00:14
2 | userB | 22 | 2014-01-22 12:26:06
I tried to achieve this by adding ORDER BY modified desc to the query, but it always returns the later score. I tried ORDER BY modified asc as well, but I got the same result
This is the classic greatest-n-per-group problem, which has been answered frequently on StackOverflow. Here's a solution for your case:
SELECT e.*
FROM entries e
JOIN (
SELECT DATE(modified) AS modified_date, MAX(score) AS score
FROM entries
GROUP BY modified_date
) t ON DATE(e.modified) = t.modified_date AND e.score = t.score
WHERE DATE(e.modified) = CURDATE()
I think this would works for you and is the simplest way:
SELECT username, MAX(score), MIN(modified)
FROM entries
GROUP BY username
This returns this in your case:
"userB";22;"2014-01-22 12:26:06"
"userA";22;"2014-01-22 08:00:14"
However, I think what you want (in your example would be wrong) the most recent row. To do it, you need this:
SELECT username, MAX(score), MAX(modified)
FROM entries
GROUP BY username
Which returns:
"userB";22;"2014-01-22 18:49:01"
"userA";22;"2014-01-22 16:13:22"