what will be the simple mysql query for this - mysql

I want to get the customer info where customer id should be 2 and the log_id should be maximum value
i tried below query but it is fetching first record found.
What will be the simple query
mysql> select * from log_customer where customer_id =2 group by customer_id having max(log_id);
+--------+------------+-------------+---------------------+-----------+----------+
| log_id | visitor_id | customer_id | login_at | logout_at | store_id |
+--------+------------+-------------+---------------------+-----------+----------+
| 2 | 56 | 2 | 2010-02-19 19:34:45 | NULL | 1 |
+--------+------------+-------------+---------------------+-----------+----------+
1 row in set (0.00 sec)
mysql> select * from log_customer where customer_id =2 limit 5;
+--------+------------+-------------+---------------------+---------------------+----------+
| log_id | visitor_id | customer_id | login_at | logout_at | store_id |
+--------+------------+-------------+---------------------+---------------------+----------+
| 2 | 56 | 2 | 2010-02-19 19:34:45 | NULL | 1 |
| 3 | 114 | 2 | 2010-02-23 17:31:55 | NULL | 1 |
| 31 | 1854 | 2 | 2010-03-08 18:31:28 | 2010-03-08 18:56:49 | 1 |
| 32 | 1992 | 2 | 2010-03-09 01:12:43 | NULL | 1 |
| 33 | 2304 | 2 | 2010-03-09 14:42:39 | NULL | 1 |
+--------+------------+-------------+---------------------+---------------------+----------+
Please do not suggest order by log_id desc I don't want to get in this way

SELECT *
FROM log_customer
WHERE customer_id = 2
AND log_id = (Select Max(Log_id)
FROM log_Customer
WHERE customer_id = 2)
That should do the trick
Edit without the Where:
SELECT *
FROM log_customer
WHERE log_id = (Select Max(Log_id)
FROM log_Customer
WHERE customer_id = 2)

Maybe this way:
SELECT *
FROM Log_Customer
WHERE Customer_Id = 2
AND Log_Id = (SELECT Max(Log_Id)
FROM Log_Customer
WHERE Customer_Id = 2)
A sub-select usually isn't bad as far as the execution plan is concerned.

select * from log_customer
left join
(select max(log_id) as max_id from log_customer where customer_id=2)
as log_customer2
on log_customer.log_id=log_customer2.max_id
where log_customer.customer_id=2;
oh damn...
select * from log_customer where customer_id=2 order by log_id desc limit 1;

Related

MYSQL - get first record based on column value

I have the following employee_sequence table
| id | employee_id | sequence_id | is_completed |
|----|:-----------:|:-----------:|:------------:|
| 1 | 12 | 3 | 1 |
| 2 | 12 | 4 | 1 |
| 3 | 10 | 3 | 1 |
| 4 | 10 | 4 | 0 |
I am looking for how to get, in 1 query, the first row having is_completed = 0 for an employee. If no such row for that employee, then take first row having is_completed = 1
Example for employee_id = 12 (there is no is_completed = 0, so first row having is_completed = 1)
| id | employee_id | sequence_id | is_completed |
|----|:-----------:|:-----------:|:------------:|
| 1 | 12 | 3 | 1 |
Example for employee_id = 10 (first row having is_completed = 0)
| id | employee_id | sequence_id | is_completed |
|----|:-----------:|:-----------:|:------------:|
| 4 | 10 | 4 | 0 |
You can use row_number(), if yu are running MySQL 8.0; assumuming that id can be used to order the records, you would phrase this as:
select *
from (
select es.*, row_number() over(partition by employee_id order by is_completed, id) rn
from employee_sequence es
) es
where rn = 1
In ealier version, an alternative is a correlated subquery with a row-limiting clause:
select *
from employee_sequence es
where es.id = (
select es1.id
from employee_sequence es1
where es1.employee_id = es.employee_id
order by es1.is_completed, es.id
limit 1
)
If you want this per employee (as your question suggests):
select es.*
from employee_sequence es
where es.employee_id = 12
order by is_completed, id
limit 1;
Here is a db<>fiddle.
If you are running something less than MySql 8 then:
select * from employee_sequence e1
where e1.id = (
select e2.id
from employee_sequence e2
where e2.employee_id = e1.employee_id
order by e2.is_completed, e2.sequence_id
limit 1
);
| id | employee_id | sequence_id | is_completed |
| --- | ----------- | ----------- | ------------ |
| 1 | 12 | 3 | 1 |
| 4 | 10 | 4 | 0 |
View on DB Fiddle

select sub sub sql query on 3 tables

table1 - customer_data
c_id (int)
name (varchar)
table2 - account_data
a_id (int)
c_id (int) -> use customer_data.c_id
plan_id (int)
table3 - game_data
g_id (int)
sort (int)
a_id (int) -> use account_data.a_id
game_name (var)
I using sub-query to select the game_data from account_data.
like that:
SELECT `a_id`,`c_id`,`plan_id`,
(SELECT `game_name` FROM `game_data` WHERE `a_id` = a.`a_id` ORDER BY `sort` ASC LIMIT 1) as main_game
FROM `accoubt_data` AS a WHERE `a_id` > 0 ORDER BY `id` DESC
this sql is work for select game_data from account_data
But I can't using it to select game_data from customer_data
How can I do something?
customer_data
+----------------------+
| c_id | name |
+----------------------+
| 1001 | Joe |
| 1002 | John |
| 1003 | David |
+----------------------+
account_data
+-------------------------------------+
| a_id | cid | plan_id |
+-------------------------------------+
| 6015 | 1002 | 34 |
| 6028 | 1003 | 1 |
| 6088 | 1001 | 9 |
+-------------------------------------+
game_data
+--------------------------------------+
| g_id | game_name | a_id |
+--------------------------------------+
| 8011 | GTA5 | 6015 |
| 8023 | WWE2016 | 6028 |
| 8088 | FIFA16 | 6088 |
| 8095 | FIFA17 | 6088 |
| 8086 | FIFA15 | 6088 |
+--------------------------------------+
this is base select
I need get this data from customer_data.c_id
+--------------------------------------+
| c_id | name | frist_game |
+--------------------------------------+
| 1001 | Joe | FIFA15 |
| 1002 | John | GTA5 |
| 1003 | David | WWE2016 |
+--------------------------------------+
c_id > a_id > g_id ORDER BY sort ASC
Try with join:
SELECT c.`c_id`,c.name,
(SELECT `game_name` FROM `game_data`
WHERE `a_id` = a.`a_id`
ORDER BY `sort` ASC LIMIT 1) as first_game
FROM `accoubt_data` a
JOIN customer_data c ON(a.c_id = c.c_id)
WHERE a.`a_id` > 0
ORDER BY a.`id` DESC
try this
SELECT cd.c_id,cd.name, first_game
FROM account_data ad
inner join game_data gd ON ad.a_id = gd.a_id order by gd.g_id,ad.a_id as games
inner join customer_data cd on games.c_id = cd.c_id order by cd.c_id
Hope this works.

How to select last row for specific user?

I have a table like this:
// requests
+----+----------+-------------+
| id | id_user | unix_time |
+----+----------+-------------+
| 1 | 2353 | 1339412843 |
| 2 | 2353 | 1339412864 |
| 3 | 5462 | 1339412894 |
| 4 | 3422 | 1339412899 |
| 5 | 3422 | 1339412906 |
| 6 | 2353 | 1339412906 |
| 7 | 7785 | 1339412951 |
| 8 | 2353 | 1339413640 |
| 9 | 5462 | 1339413621 |
| 10 | 5462 | 1339414490 |
| 11 | 2353 | 1339414923 |
| 12 | 2353 | 1339419901 |
| 13 | 8007 | 1339424860 |
| 14 | 7785 | 1339424822 |
| 15 | 2353 | 1339424902 |
| 16 | 2353 | 1466272801 |
| 17 | 2353 | 1466272805 |
+----+----------+-------------+
I'm trying to get last row which is related to specific user. For example for this user id_user = 7785 I want to select this row:
| 14 | 7785 | 1339424822 |
And here is my query:
SELECT unix_time AS last_seen
FROM requests WHERE id = '7785'
ORDER BY unix_time DESC
LIMIT 1
But my query doesn't select any row. What's wrong?
SQL fiddle
Also as a note, can you please tell me should I create single index on id_user and uinx_time or should I create a multiple columns index on those two columns (id_user, unix_time)?
You are using the wrong column (id instead of id_user — or vice versa):
SELECT unix_time AS last_seen
FROM requests WHERE id_user = '7785'
ORDER BY unix_time DESC
LIMIT 1
Let a sub-query return each id_user with it's highest unix_time. Join with that result.
select t1.*
from tablename t1
join (select id_user, max(unix_time) as unix_time
from tablename
group by id_user) t2
on t1.id_user = t2.id_user and t1.unix_time = t2.unix_time
Will return all users and their latest login.
Add WHERE id_user = '7785' if info about a single user is wanted.
In the WHERE condition you are comparing id with id of id_user.
Your mistake is at line two, it should be like:
SELECT unix_time AS last_seen
FROM requests WHERE id_user = '7785'
ORDER BY unix_time DESC
LIMIT 1
You have:
WHERE id = '7785'
If you want the row: | 7 | 7785 | 1339412951 |
You need something like:
SELECT TOP 1 unix_time AS last_seen
FROM requests WHERE id_user = '7785'
ORDER BY unix_time DESC
This will take the top result of the query where the user_ID equals '7785'. The 'ORDER BY unix_time DESC' puts the values with the highest unit time at the top so it will by the last request that user has had.
You can use below query it will help you
SELECT SUBSTRING_INDEX(id,',',1) AS id ,SUBSTRING_INDEX(id_user,',',1) AS id_user, unix_time FROM
(SELECT GROUP_CONCAT(id ORDER BY unix_time DESC ) AS id, GROUP_CONCAT(id_user ORDER BY unix_time DESC ) AS id_user ,MAX(unix_time) AS unix_time FROM test_71 GROUP BY id_user
HAVING id_user='7785' ) t ;

Mysql Calculate rank of teams from different rows

I'm trying to build a kind of peddy paper. For that I have the following tables:
teams
CREATE TABLE `teams` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`creator_id` int(11) NOT NULL,
`friend_id` int(11) DEFAULT NULL,
`team_name` varchar(128) NOT NULL,
PRIMARY KEY (`id`)
);
team_log
CREATE TABLE IF NOT EXISTS `progress_tracker` (
`id` int(8) NOT NULL AUTO_INCREMENT,
`user_id` int(8) NOT NULL,
`team_id` int(11) NOT NULL,
`date` date NOT NULL,
`clues_found` int(11) NOT NULL,
`clues_to_find` int(11) NOT NULL,
PRIMARY KEY (`id`)
);
Each team is composed by two users;
Each user starts out with a variable number of clues found;
clues_found can either increase or decrease. No guarantee that the highest number is the latest;
I need to get a rank of the teams (in percentage) based on the average of the number of clues the user found since they joined (for both users in a team) - clues_found on the row with biggest date minus clues_found on the record with lowest date).
For instance if I have the following data for each table:
teams table data
+--------+------------+------------+---------------+
| id | creator_id | friend_id | team_name |
+--------+------------+------------+---------------+
| 1 | 25 | 28 | Test1 |
| 2 | 31 | 5 | Test2 |
+--------+------------+------------+---------------+
team_log table data
+--------+---------+---------+------------+-------------+---------------+
| id | user_id | team_id | date | clues_found | clues_to_find |
+--------+---------+---------+------------+-------------+---------------+
| 1 | 25 | 1 | 2013-01-6 | 3 | 24 |
| 2 | 25 | 1 | 2013-01-8 | 7 | 24 |
| 3 | 25 | 1 | 2013-01-10 | 10 | 24 |
| 4 | 28 | 1 | 2013-01-8 | 5 | 30 |
| 5 | 28 | 1 | 2013-01-14 | 20 | 30 |
| 6 | 31 | 2 | 2013-01-11 | 6 | 14 |
| 7 | 5 | 2 | 2013-01-9 | 2 | 20 |
| 8 | 5 | 2 | 2013-01-10 | 10 | 20 |
| 9 | 5 | 2 | 2013-01-12 | 14 | 20 |
+--------+---------+---------+------------+-------------+---------------+
Desired Result
+-------------+---------------------+
| team_id | team_percentage |
+-------------+---------------------+
| 1 | 39,58333333 |
| 2 | 30 |
+-------------+---------------------+
As a reference this is an intermediate representation which might help to understand:
+-------------+---------+---------------------+
| user_id | team_id | precentage_per_user |
+-------------+---------+---------------------+
| 25 | 1 | 29,16666667 |
| 28 | 1 | 50 |
| 31 | 2 | 0 |
| 5 | 2 | 60 |
+-------------+---------+---------------------+
So far I have the following sql:
SELECT STRAIGHT_JOIN
tl2.team_id, (tl2.weight - tl1.weight)*100/tl2.clues_to_find
from
( select
team_id,user_id,clues_found
FROM
`team_log`
where 1
group by
team_id, user_id
order by
`date` ) base
join (select team_id, user_id, clues_found, clues_to_find from `team_log` where user_id = base.user_id and team_id = base.team_id group by team_id, user_id order by `date` desc) tl2
But this returns an error as I'm not allowed to use base.user_id inside the second query. I'm also not very sure I'm heading in the right direction.
Can anyone help please?
Here's another query that will produce the correct result:
SELECT calc.team_id, AVG((calc.end_clues - calc.start_clues)/calc.total_clues*100) as team_percentage
FROM
(SELECT log1.user_id, log1.team_id, log1.clues_found as start_clues, log2.clues_found as end_clues, log2.clues_to_find as total_clues FROM team_log log1
JOIN
(SELECT MIN(id) as start_id, MAX(id) as end_id FROM team_log GROUP BY user_id) ids
ON ids.start_id = log1.id
JOIN team_log log2 ON ids.end_id = log2.id) calc
GROUP BY team_id
ORDER BY team_id;
And the SQL Fiddle-link...
Please take a look at this and comment:
SQLFIDDLE DEMO
Team pct:
select z.team_id, avg(z.pct) as teampct
from (
select x.user_id, y.team_id, x.mndate,
y.mxdate, x.mnclues_found,
y.mxclues_found,
(((y.mxclues_found - x.mnclues_found)*100)
/y.mxclues_tofind) pct
from
(select user_id, team_id, min(date) mndate,
min(clues_found) as mnclues_found
from team_log
group by user_id, team_id) x
left join
(select user_id, team_id, max(date) mxdate,
max(clues_found) as mxclues_found,
max(clues_to_find) as mxclues_tofind
from team_log
group by user_id, team_id) y
on x.user_id = y.user_id and
x.team_id = y.team_id) z
group by z.team_id
;
Results 1:
| USER_ID | TEAM_ID | MNDATE | MXDATE | MNCLUES_FOUND | MXCLUES_FOUND | PCT |
-------------------------------------------------------------------------------------
| 5 | 2 | 13-01-09 | 13-01-12 | 2 | 14 | 60 |
| 25 | 1 | 13-01-06 | 13-01-10 | 3 | 10 | 29.1667 |
| 28 | 1 | 13-01-08 | 13-01-14 | 5 | 20 | 50 |
| 31 | 2 | 13-01-11 | 13-01-11 | 6 | 6 | 0 |
Results final:
| TEAM_ID | TEAMPCT |
----------------------
| 1 | 39.58335 |
| 2 | 30 |
This is a bit ugly, but should work:
select
team_id,
AVG(percentage_per_user) as team_percentage
from (select
team_id,
user_id,
((select clues_found from progress_tracker as x
where x.user_id = m.user_id order by x.date desc limit 0, 1)
- (select clues_found from progress_tracker as y
where y.user_id = m.user_id order by y.date asc limit 0, 1))
/ MAX(clues_to_find)
as percentage_per_user
from progress_tracker as m
group by team_id, user_id
) as userScore
group by team_id
order by team_percentage desc;
Note the inner query run by itself will yield your intermediate "per-user" result.
SQLFiddle
SELECT `team_id`,
(SUM(CASE WHEN b.`date` IS NULL THEN 0 ELSE `clues_found` * 100 / `clues_to_find` END) -
SUM(CASE WHEN c.`date` IS NULL THEN 0 ELSE `clues_found` * 100 / `clues_to_find` END)) / 2
FROM `team_log` a
LEFT JOIN (
SELECT `team_id`, `user_id`, MAX(date) AS `date`
FROM `team_log`
GROUP BY `team_id`, `user_id`) b
USING (`team_id`, `user_id`, `date`)
LEFT JOIN (
SELECT `team_id`, `user_id`, MIN(date) AS `date`
FROM `team_log`
GROUP BY `team_id`, `user_id`) c
USING (`team_id`, `user_id`, `date`)
GROUP BY `team_id`
Since you say there are always two team members, I've used /2. It would be slightly more complex for variable-sized teams.

sql group query with order by and limit

My table strucutre is as follows
| id | cmp | empid | empname | ttm
+------+----------+-------+---------+------
| 2 | xyz | 12 | swap | 2
| 2 | xyz | 12 | sag | 3
| 2 | xyz | 14 | azr | 1
| 3 | pqr | 2 | ron | 2
| 3 | pqr | 22 | rah | 1
| 3 | pqr | 32 | pra | 5
I have done query on that like as follows
(select * from test.companies where id = '2' order by ttm desc limit 2)
union
(select * from test.companies where id = '3' order by ttm desc limit 2);
it will give output as follows
| id | cmp | empid | empname | ttm
+------+----------+-------+---------+------
| 2 | wissen | 12 | sag | 3
| 2 | wissen | 12 | swap | 2
| 3 | prolinkd | 32 | pra | 5
| 3 | prolinkd | 2 | ron | 2
but i want output as follows
| id | cmp | empid | empname | ttm
+------+----------+-------+---------+------
| 3 | prolinkd | 32 | pra | 5
| 3 | prolinkd | 2 | ron | 2
| 2 | wissen | 12 | sag | 3
| 2 | wissen | 12 | swap | 2
means which company has maximum ttm it will be shown first
If some one knows plz reply
Thanks
Rather ugly looking, and ugly sounding, but it should do what you want. It retrieves the "maxttm" for each company with each record, then uses that in sorting to allow you to assign priority to companies based on their highest ttm.
SELECT * FROM (
(SELECT *,
(SELECT ttm FROM test.companies ic WHERE ic.id = oc.id ORDER BY ttm DESC LIMIT 1) AS maxttm
FROM test.companies oc WHERE id = '2' ORDER BY ttm DESC LIMIT 2)
UNION
(SELECT *,
(SELECT ttm FROM test.companies ic WHERE ic.id = oc.id ORDER BY ttm DESC LIMIT 1) AS maxttm
FROM test.companies oc WHERE id = '3' ORDER BY ttm DESC LIMIT 2)
) AS myunion ORDER BY maxttm, id;
PS. thanks to inti whose query I shamelessly based this on.
I think this will work:
SELECT * FROM (
(select * from test.companies where id = '2' order by ttm desc limit 2)
union
(select * from test.companies where id = '3' order by ttm desc limit 2)
) as myunion ORDER BY ttm;
gets what you need, and orders it by ttm.
select *
from test.companies
where id in ('2','3')
and ttm > 1
order by ttm desc, id