MySQL Get exactly one entry per id by multiple ids - mysql

my problem is that I want this:
SELECT * FROM table
WHERE userId = 7243
ORDER BY date desc LIMIT 1
But for multiple ids in one request.
I tried this:
SELECT * FROM table
WHERE userId IN (7243, 1)
GROUP BY userId
ORDER BY date desc
But the order by seems to be ignored. Do anyone has a solution for me? Thank you

If you want the max date record for each of the two IDs, then you may use a subquery:
SELECT t1.*
FROM yourTable t1
INNER JOIN
(
SELECT userId, MAX(date) AS max_date
FROM yourTable
WHERE userId IN (7243, 1)
GROUP BY userId
) t2
ON t1.userId = t2.userId AND t1.date = t2.max_date
WHERE
t1.userId IN (7243, 1);
This is the just greatest-value-per-group question with a slight twist, namely that you only want to see two of the possible groups in the output.
As #Raymond commented below, an index on (userId, date) should greatly speed up the t2 subquery. I am not sure if this index would help beyond that, but it should make a difference.

Related

Need to display data from one column into the same column on a separate row which the identifier is the same

Hi I have the following example table
ID
StartDate
1
05/12/2007
1
31/05/2010
I need it so that there is only one row per ID with the earliest start date as follows:
ID
StartDate
1
05/12/2007
Is there a way to do this in mySQL?
Many Thanks
Yes, you can simply do this, first arrange The items date wise and then apply the group by clause.
query may be:
SELECT FROM `TABLE` GROUP BY `ID` ORDER BY `StartDate`;
First group by then order by.
There are a couple of options - e.g. null left joins - but the simplest approach is probably something like this (and I'm assuming a unique column of 'UID'):
select t1.id, t1.startdate from myTable as t1
join myTable as t2 on t2.uid = (select uid from myTable where id = t1.id order by
startdate limit 1)
where t1.uid = t2.uid;
Simply:
SELECT ID, MIN(StartDate)
FROM your_table_name
GROUP BY ID

How to get the maximum and not duplicated data in my table in mysql?

I table data is like this:
id car_id create_time remark
6c3befd0201a4691 4539196f55b54523986535539ed7beef 2017-07-1 16:42:49 firstcar
769d85b323bb4a1c 4539196f55b54523986535539ed7beef 2017-07-18 16:42:49 secondcar
984660c4189e499 575d90e340d14cf1bef4349b7bb5de9a 2017-07-3 16:42:49 firstjeep
I want to get the newest data. It means if there have two same car_id, I want to get only one according the newest time. How to write?
I try to write this, but I find it may wrong. If the other record may have the same create_time? How to fix that?
SELECT * FROM t_decorate_car
WHERE create_time IN
(SELECT tmptime FROM
(SELECT MAX(create_time),tmptime,car_id
FROM decorate
GROUP BY car_id
) tmp
)
One canonical way to handle this is to join your table to a subquery which finds the latest record for each car_id. This subquery serves as a filter to remove the older records you don't want to see.
SELECT t1.*
FROM t_decorate_car t1
INNER JOIN
(
SELECT car_id, MAX(create_time) AS max_create_time
FROM t_decorate_car
GROUP BY car_id
) t2
ON t1.car_id = t2.car_id AND
t1.create_time = t2.max_create_time
By the way, if you want to continue down your current road, you can also solve this using a correlated subquery:
SELECT t1.*
FROM t_decorate_car t1
WHERE t1.create_time = (SELECT MAX(t2.create_time) FROM t_decorate_car t2
WHERE t2.car_id = t1.car_id)
You were on the right track but you never connected the subquery to the main query using the right WHERE clause.

mysql/php, group by userID, sort by time

I have a table which holds the userID, highscore, and a timestamp.
I would like to sort by timestamp, so that the newest entries are at the top, and also, don't show any userID twice in the list, ergo, they need to be grouped.
I also need it to be sorted by score.
$sql="SELECT * FROM $table GROUP BY userID ORDER BY time DESC";
$sql2="SELECT * FROM $table GROUP BY userID ORDER BY score DESC";
At this moment, I see that Group by is done first, so I probably just get some random timestamps/stamps. I need to order them first, them Group them. However, I get errors if I switch Group by and Order by.
Could anybody help me out here? Thanks.
GROUPing is always done before ORDERing. To order records before grouping, there are 2 approaches:
ORDER BY in subquery and then apply GROUP BY. This is not usually a better approach since running a subquery is very expensive, especially if you have many records. For small number of records, this is going to be fine.
$sql="SELECT * FROM (SELECT * FROM $table ORDER BY time DESC) GROUP BY userID";
A better solution is to get the MAX(time) in a subquery and then join that to your table on both the userID and the max time.
SELECT p1.*
FROM $table t1
INNER JOIN
(
SELECT max(time) MaxTime, userID
FROM $table
GROUP BY userID
) t2
ON t1.userID = t2.userID
AND t1.time = t2.MaxTime
order by t1.time DESC;
I have written them from top of my head.
HTH

Count subselect elements according to parent id

I'm having this MySQL Query
SELECT
t1.article_id,
t1.user_id,
t1.like_date,
(
SELECT
COUNT(*)
FROM liketbl t2
WHERE
t1.article_id=t2.article_id
) as totallike
FROM liketbl t1
WHERE
user_id = 1;
I need to get article id, user id and liked date in one run with the number of total entries.
Subselect is, in my opinion the easiest was to achieve this.
(Don't want to run several queries in client entviroment.
But is not working.
Don't know why, help is appreceated.
try this :
SELECT t1.article_id,
t1.user_id,
t1.like_date,
COUNT(*) as totallike
FROM liketbl t1 inner join liketbl t2 on t1.article_id=t2.article_id
WHERE user_id = 1
group by t1.article_id,t1.user_id,t1.like_date;
My guess is that you need to filter on user_id = 1 in the subquery to get what you expect.
The where only operates on the outer select.
This should work
SELECT
t1.article_id,
t1.user_id,
t1.like_date,
count(SELECT * FROM liketbl t2 WHERE
t1.article_id=t2.article_id ) as totallike
FROM liketbl t1
WHERE
user_id = 1;
Scalar Subqueries tend to be the worst case, it's usually more efficient to rewrite them.
Depending on the number of rows in both tables this is another approach using a Derived Table:
SELECT
t1.article_id
,t1.user_id
.t1.like_date
,t2.totallike
FROM liketbl t1
JOIN
(
SELECT
article_id
,COUNT(*) AS totallike
FROM liketbl
GROUP BY article_id
) AS t2
ON t1.article_id=t2.article_id
WHERE
user_id = 1;

How do I write this kind of query (returning the latest avaiable data for each row)

I have a table defined like this:
CREATE TABLE mytable (id INT NOT NULL AUTO_INCREMENT, PRIMARY KEY(id),
user_id INT REFERENCES user(id) ON UPDATE CASCASE ON DELETE RESTRICT,
amount REAL NOT NULL CHECK (amount > 0),
record_date DATE NOT NULL
);
CREATE UNIQUE INDEX idxu_mybl_key ON mytable (user_id, amount, record_date);
I want to write a query that will have two columns:
user_id
amount
There should be only ONE entry in the returned result set for a given user. Furthermore, the amount figure returned should be the last recoreded amount for the user (i.e. MAX(record_date).
The complication arises because weights are recorded on different dates for different users, so there is no single LAST record_date for all users.
How may I write (preferably an ANSI SQL) query to return the columns mentioned previously, but ensuring that its only the amount for the last recorded amount for the user that is returned?
As an aside, it is probably a good idea to return the 'record_date' column as well in the query, so that it is eas(ier) to verify that the query is working as required.
I am using MySQL as my backend db, but ideally the query should be db agnostic (i.e. ANSI SQL) if possible.
First you need the last record_date for each user:
select user_id, max(record_date) as last_record_date
from mytable
group by user_id
Now, you can join previous query with mytable itself to get amount for this record_date:
select
t1.user_id, last_record_date, amount
from
mytable t1
inner join
( select user_id, max(record_date) as last_record_date
from mytable
group by user_id
) t2
on t1.user_id = t2.user_id
and t1.record_date = t2.last_record_date
A problem appears becuase a user can have several rows for same last_record_date (with different amounts). Then you should get one of them, sample (getting the max of the different amounts):
select
t1.user_id, t1.record_date as last_record_date, max(t1.amount)
from
mytable t1
inner join
( select user_id, max(record_date) as last_record_date
from mytable
group by user_id
) t2
on t1.user_id = t2.user_id
and t1.record_date = t2.last_record_date
group by t1.user_id, t1.record_date
I do not now about MySQL but in general SQL you need a sub-query for that. You must join the query that calculates the greatest record_date with the original one that calculates the corresponding amount. Roughly like this:
SELECT B.*
FROM
(select user_id, max(record_date) max_date from mytable group by user_id) A
join
mytable B
on A.user_id = B.user_id and A.max_date = B.record_date
SELECT datatable.* FROM
mytable AS datatable
INNER JOIN (
SELECT user_id,max(record_date) AS max_record_date FROM mytable GROUP BS user_id
) AS selectortable ON
selectortable.user_id=datatable.user_id
AND
selectortable.max_record_date=datatable.record_date
in some SQLs you might need
SELECT MAX(user_id), ...
in the selectortable view instead of simply SELECT user_id,...
The definition of maximum: there is no larger(or: "more recent") value than this one. This naturally leads to a NOT EXISTS query, which should be available in any DBMS.
SELECT user_id, amount
FROM mytable mt
WHERE mt.user_id = $user
AND NOT EXISTS ( SELECT *
FROM mytable nx
WHERE nx.user_id = mt.user_id
AND nx.record_date > mt.record_date
)
;
BTW: your table definition allows more than one record to exist for a given {id,date}, but with different amounts. This query will return them all.