My table payment_status have these fields:
id
payment_id
status
created
created_by
Many entries could have the same payment_id... So, I want to get the last status for one payment_id...
I have this request that work but take too much time to load... I would like to have an optimize version to group by payment_id and take the last status.
SELECT pstatus.*
FROM `payment_status` AS pstatus
WHERE pstatus.id = (
SELECT id
FROM `payment_status`
WHERE pstatus.status = '200'
ORDER BY created DESC
LIMIT 1
)
GROUP BY pstatus.payment_id
ORDER BY pstatus.payment_id DESC
Try this query -
SELECT t1.* FROM payment_status t1
JOIN (SELECT payment_id, MAX(created) max_created
FROM payment_status
GROUP BY payment_id
) t2
ON t1.payment_id = t2.payment_id AND t1.created = t2.max_created;
...then add WHERE conditions you need.
Try to use JOIN:
SELECT p1.*
FROM payment_status p1
INNER JOIN
(
SELECT id, MAX(created) MaxCreated
FROM payment_status
WHERE status = '200'
GROUP BY id
) p2 ON p1.id = p2.id AND p1.created = p2.MaxCreated
ORDER BY p1.payment_id DESC
this should work
SELECT *
FROM payment_status
WHERE status = '200'
ORDER BY created DESC
LIMIT 1
shouldn't yo ujust be able to do this?:
(assuming that created is the timestamp, so "last" = "most recent")
SELECT pstatus.*
FROM `payment_status` AS pstatus
GROUP BY pstatus.payment_id, pstatus.status
ORDER BY pstatus.payment_id DESC, pstatus.created DESC
each row returns should have the payment_id with the most recent status.
I suppose you are using MySQL database.
Here I have a solution is fast and readable:
select
substring_index(
group_concat(status order by created desc)
, ',', 1
) as status_latest
from payment_status
group by payment_id
I'm quite sure it's fast than others SQL statement,
You may try it.
Related
I have a History table that represents messages that are stored by some sort of chat program.
It has a user id, message & datetime. (specified on: http://sqlfiddle.com/#!9/49fcefb/5)
Now, what I want is to have a result which contains:
The max amount of messages typed by date
What user has the most messages and howmany messages this user typed)
I got it working, but I find the query rather slow, I think its because of the last GROUP BY (GROUP BY b.cnt) as this will group over all the records found.
Query:
SELECT b.cnt as dayCount, a.cnt as userCount, a.userid as userId, b.date
FROM (
select date_added as date, user_id as userid, count(*) as cnt from history group by userid, day(date_added),month(date_added),year(date_added)
) a
INNER JOIN (
select date_added as date, count(*) as cnt from history group by day(date_added),month(date_added),year(date_added)
) b ON year(a.date) = year(b.date)
AND month(a.date) = month(b.date)
AND day(a.date) = day(b.date)
GROUP BY b.cnt
ORDER BY dayCount desc, userCount desc limit 10;
Can someone advice me on how to solve this? Maybe with another sort of query?
Thanks in advance!
You can try using windows function with Subquery to get the same result.
select SQ.daycount,SQ.usercount,SQ.user_id, SQ.date1 from (
select sum(count(Message)) over (partition by date(date_added)) as daycount, --to get max amount of msg by date
max(count(Message)) over (partition by date(date_added)) as maxuser, -- to identify user with most msg
count(Message) as usercount,
date(date_added) as date1,user_id from history
group by date1,user_id ) SQ
where SQ.usercount=SQ.maxuser
Check the Fiddle here
seems you are joining with wrong criteria.
first table is getting the # of users, 2nd table is getting the #of days per user_id. see dbfiddle
SELECT b.cnt as dayCount, a.cnt as userCount, a.userid as userId, b.date
FROM (
select
user_id as userid
, count(*) as cnt
from history
group by userid
) a
LEFT JOIN (
select cast(date_added as date) as date
, count(*) as cnt
, user_id as userid
from history
group by cast(date_added as date)
) b ON a.userid = b.userid
ORDER BY dayCount desc, userCount desc limit 10;
This is my customer table.
I want to group by emp_id alongwith the count. But Group By gets the 'first' record and not the 'newest' one.
I have tried various queries, like this
SELECT id, emp_id, COUNT( * ) AS count, created_at
FROM customer c
WHERE created_at = (
SELECT MAX( created_at )
FROM customer c2
WHERE c2.emp_id = c.emp_id
)
GROUP BY emp_id
ORDER BY created_at DESC
LIMIT 0 , 30
But cannot get the count. Please help.
Edit: this answer doesn't help to obtain count
Try joining to a subquery:
SELECT c1.id, c1.emp_id, c1.created_at, c2.cnt
FROM customer c1
INNER JOIN
(
SELECT emp_id, MAX(created_at) AS max_created_at, COUNT(*) AS cnt
FROM customer
GROUP BY emp_id
) c2
ON c1.emp_id = c2.emp_id AND c1.created_at = c2.max_created_at;
please try this
SELECT cust1.id, cust1.emp_id, cust1.created_at, cust2.cnt
FROM customer cust1
INNER JOIN
(
SELECT emp_id, MAX(created_at) AS max_created_at, COUNT(*) AS count
FROM customer
GROUP BY emp_id
) cust2
ON cust1.emp_id = cust2.emp_id AND cust1.created_at = cust2.max_created_at;
I have a TABLE user_orders with fields -->
order_id int(10),
user_id int(10),
order_payment_id int(10)
order_created int(10)
I want to find the last order_payment_id used for each user_id. I try
SELECT order_payment_id, user_id , MAX(order_id) as lastone
FROM user_orders
GROUP BY user_id;
but the result is wrong
You can use a self-join to filter out the relevant data
SELECT o1.*
FROM user_orders o1
JOIN
(
SELECT user_id, MAX(order_created) as lastone
FROM user_orders
GROUP BY user_id
) o2 on o1.user_id = o2.user_id
and o1.order_created = o2.lastone
GROUP BY o1.user_id
The general GROUP BY rule is:
If a GROUP BY clause is specified, each column reference in the SELECT list must either identify a grouping column or be the argument of a set function.
SELECT order_payment_id, user_id , order_id as lastone
FROM user_orders uo
WHERE order_id = (select MAX(order_id) from user_orders
where user_id = uo.user_id)
The MAX should be in the WHERE clause, or it will select the maximum order_id for the whole table.
SELECT order_payment_id, user_id ,order_id as lastone
FROM user_orders u1
WHERE u1.order_id = (SELECT MAX(order_id)
FROM user_orders u2
WHERE u1.user_id = u2.user_id);
Using this query, you can get rid of the GROUP BY except if order_id is not unique.
That way you'll get the last order associated with the user.
I want to select the last (datetime) record_version ordered by datetime DESC, for every account_id
SELECT *
FROM `record_versions`
WHERE record_id='26'
GROUP BY `account_id`
ORDER BY datetime DESC
It returns only one record for account_id, but it's not the last
You can use a self join to get your desired result ,inner query will get maximum of your datetime column per account_id and it will join the rows from outer query with the latest datetime value
SELECT
r.*
FROM
`record_versions` r
JOIN
(SELECT
MAX(`datetime`) `datetime`,
account_id
FROM
record_versions
GROUP BY account_id) t
ON (
r.account_id = t.account_id
AND r.datetime = t.datetime
)
WHERE r.record_id = '26'
I'm trying to get a subset of records in a GROUP BY, I've seen a lot of crazy solutions out there, but they just seem too complicated, is there any more efficient way to do this.
SELECT user_id, GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items
FROM wb_user_book_current_item GROUP BY user_id
So this will return me all the current items for all users which is okay so far. But I only want the ten most recent items. Adding ORDER BY to the GROUP_CONCAT helps, but it still doesn't give me the last ten records.
EDIT
If I do something like this and hard code the user_id then I can get the results I want for that one user, problem is combining it so that I don't need to hard code the user_id and can for instance just get ALL users last ten items
SELECT GROUP_CONCAT(cp2.item_id) AS items
FROM (SELECT cp.user_id, cp.item_id
FROM wb_user_book_current_item cp
WHERE cp.user_id=1 ORDER BY cp.`timestamp`
LIMIT 10) AS cp2
GROUP BY cp2.user_id
This is a difficult problem, but how about this:
SELECT user_id, GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items
FROM wb_user_book_current_item T
WHERE NOT EXISTS
(
SELECT 1
FROM wb_user_book_current_item T2
WHERE T2.user_id = T.user_id
ORDER BY T2.`timestamp` DESC
LIMIT 10,1
)
OR T.`timestamp` > (
SELECT T2.`timestamp`
FROM wb_user_book_current_item T2
WHERE T2.user_id = T.user_id
ORDER BY T2.`timestamp` DESC
LIMIT 10,1
)
GROUP BY user_id
This of course assumes you won't have two rows with the same timestamp for the same user.
If your timestamp field is always a positive integer, you can also replace the NOT EXISTS...OR with a COALESCE:
SELECT user_id, GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items
FROM wb_user_book_current_item T
WHERE T.`timestamp` > COALESCE((
SELECT T2.`timestamp`
FROM wb_user_book_current_item T2
WHERE T2.user_id = T.user_id
ORDER BY T2.`timestamp` DESC
LIMIT 10,1
), 0)
GROUP BY user_id
Original answer, but apparently MySQL doesn't understand how to do this properly and complains the subselect returns multiple rows. Of course we want multiple rows; it's a GROUP_CONCAT. Grr.
Unfortunately, I think there's no real way around using a subquery:
SELECT T.user_id,
GROUP_CONCAT((SELECT T2.item_id
FROM wb_user_book_current_item T2
WHERE T2.user_id = T.user_id
ORDER BY T2.`timestamp`
LIMIT 10)) AS items
FROM wb_user_book_current_item T
GROUP BY user_id
Otherwise, adding LIMIT anywhere else will either limit the number of groups, or limit from the total recordset over the table (and not the group) - neither of which are what you are trying to achieve.
So came across a nice solution here that works pretty well.
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
It's something like this put all together:
SET #num := 0, #user_id := '';
SELECT cp2.user_id, CONCAT(cp2.item_id) AS items
FROM (
SELECT cp.user_id, cp.item_id,
#num := IF(#user_id = cp.user_id, #num + 1, 1) AS row_number,
#user_id := cp.user_id AS dummy
FROM wb_user_curent_item AS cp
ORDER BY cp.user_id ASC, cp.`timestamp` DESC
) AS cp2 WHERE cp2.row_number <= 10
GROUP BY cp2.user_id
So basically it just uses the num increment to limit the records rather than using LIMIT
SELECT
i.user_id,
GROUP_CONCAT(i.item_id ORDER BY i.timestamp) AS items
FROM
( SELECT DISTINCT user_id
FROM wb_user_book_current_item
) AS du
JOIN
wb_user_book_current_item AS i
ON i.user_id = du.user_id
AND i.timestamp <= COALESCE(
( SELECT i2.item_id
FROM wb_user_book_current_item AS i2
WHERE i2.user_id = du.user_id
ORDER BY i2.timestamp ASC
LIMIT 1 OFFSET 9
)
, '2038-01-19 03:14:07')
GROUP BY
i.user_id ;
An index on (user_id, timestamp, item_id) will help efficiency.
Try this:
SELECT
user_id,
GROUP_CONCAT(item_id ORDER BY `timestamp`) AS items
FROM wb_user_book_current_item
GROUP BY user_id
LIMIT 0, 10
UPDATE: I didn't notice the GROUP_CONCAT so you will have to use sub query in conunction with LIMIT
use LIMIT
SELECT column_name(s)
FROM table_name
LIMIT number