Select tracks and the date that has maximum visits - mysql

Here is the deal. I have two tables
tracks
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| track_id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| artist_id | int(11) | YES | | NULL | |
| genre_id | int(11) | YES | | NULL | |
| track_artist | varchar(255) | YES | | NULL | |
| track_title | varchar(255) | NO | | NULL | |
| track_lyric | text | YES | | NULL | |
| track_video | varchar(255) | YES | | NULL | |
| play_url | varchar(255) | YES | | NULL | |
| shares | int(11) | NO | | 0 | |
| likes | int(11) | NO | | 0 | |
| dislikes | int(11) | NO | | 0 | |
| is_active | enum('T','F') | NO | | T | |
| created_at | int(10) | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
track_visits
+----------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------+------+-----+---------+----------------+
| track_visit_id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| track_id | int(11) | NO | MUL | NULL | |
| ip_address | varchar(255) | NO | | NULL | |
| created_at | int(10) | YES | | NULL | |
+----------------+------------------+------+-----+---------+----------------+
And the question is:
How can I select all the tracks and the date that has maximum visits for every specific track?
Regards
Nasko

Since you are using MySql, you can use this:
SELECT tracks.*, track_visits.*
FROM
tracks LEFT JOIN (
SELECT track_id, MAX(created_at) MaxCreatedAt
FROM track_visits
GROUP BY track_id) mx
ON tracks.track_id=mx.track_id
LEFT JOIN track_visits
ON mx.track_id=track_visits.track_id
AND mx.MaxCreatedAt=track_visits.created_at
GROUP BY
tracks.track_id

Related

Update a particular column from another table column in mysql

coaching_class table
Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+-------------------+-----------------------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| organization_id | int(10) unsigned | NO | MUL | NULL | |
| arena_id | int(10) unsigned | NO | MUL | NULL | |
| trainer_id | int(10) unsigned | YES | MUL | NULL | |
| type | varchar(1) | NO | | NULL | |
| sports | int(11) | NO | | NULL | |
| gender | varchar(1) | YES | | NULL | |
| max_entries | int(11) | YES | | NULL | |
| from_date | date | NO | | NULL | |
| to_date | date | YES | | NULL | |
| from_time | time | YES | | NULL | |
| to_time | time | YES | | NULL | |
| day_slot | int(11) | YES | | NULL | |
| fees | double | NO | | NULL | |
| bill_cycle | tinyint(4) | NO | | 0 | |
| due_after | tinyint(4) | YES | | 0 | |
| created_at | datetime | NO | | CURRENT_TIMESTAMP | |
| updated_at | datetime | YES | | NULL | on update CURRENT_TIMESTAMP |
| deleted_at | datetime | YES | | NULL |
coaching_class_entries table
| Field | Type | Null | Key | Default | Extra |
+-------------------+------------------+------+-----+-------------------+-----------------------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| user_id | int(10) unsigned | NO | MUL | NULL | |
| coaching_class_id | int(10) unsigned | NO | MUL | NULL | |
| fees | double | NO | | NULL | |
| bill_cycle | int(4) | NO | | 0 | |
| from_date | date | NO | | NULL | |
| to_date | date | YES | | NULL | |
| tax_group_id | int(10) unsigned | YES | MUL | NULL | |
| last_bill_date | date | YES | | NULL | |
| next_bill_date | date | YES | | NULL | |
| comments | varchar(100) | YES | | NULL | |
| created_at | datetime | NO | | CURRENT_TIMESTAMP | |
| updated_at | datetime | YES | | NULL | on update CURRENT_TIMESTAMP |
| deleted_at | datetime | YES | | NULL | |
+-------------------+------------------+------+-----+-------------------+-----
I have a added a new column bill_cycle in Coaching_class_entries table and I have the same column bill_cycle in another table called Coaching_classes . Now I want to copy the values of bill_cycle from Coaching_classes to Coaching_class_entries bill_cycle column for all the rows of coaching_class_entries. I am very new to database can anyone give me some hint please.
I think a simple update join should work here:
UPDATE Coaching_class_entries t1
INNER JOIN Coaching_classes t2
ON t1.coaching_class_id = t2.id
SET t1.bill_cycle = t2.bill_cycle;

How to add a date selection in sql

I want to be able to select classes that are starting on or after the next two hours up until the end of tomorrow's date but I am not sure of how to do this.
My current sql is below, I have only been able to select classes that are after today's date and after the current time. I want to be able to only return classes that start two hours after now up until the end of tomorrows date.
I am able to pass the current date and current time into my node.js function that will construct the sql statement. Also, I have access to moment.js library if I need to use this I could.
Any help would be appreciated.
SELECT DISTINCT b.name
, a.time
FROM class a
Inner join (SELECT class_id, count(clientid)
FROM bookings
GROUP BY class_id
HAVING count(clientid) < 10) as openClasses on
a.class_id = openClasses.class_id
JOIN class_detail b
ON a.class_id = b.id
JOIN branch c
ON a.branch_id = c.id
WHERE c.level <= ( SELECT d.level
FROM client d
WHERE d.facebook_id = 'xxxxxx'
)
AND a.date = '2016-08-17'
AND a.time >= '13.00.00';
My tables are as follows:
BOOKINGS
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| id | bigint(20) | NO | PRI | NULL | |
| CLIENT_ID | int(11) | NO | | NULL | |
| CLASS_ID | int(11) | NO | | NULL | |
| STATUS | varchar(10) | NO | | NULL | |
+-----------+-------------+------+-----+---------+-------+
mysql> show fields from BRANCH;
+---------------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+-------------+------+-----+---------+----------------+
| id | int(10) | NO | PRI | NULL | auto_increment |
| NAME | char(50) | NO | | NULL | |
| CONTACT_NO | char(50) | YES | | NULL | |
| MAP_IMG_PATH | char(200) | YES | | NULL | |
| ADDRESS | char(200) | YES | | NULL | |
| LEVEL | int(2) | NO | | NULL | |
| LOCATION | int(10) | YES | | NULL | |
| SECTOR_NAME | varchar(45) | YES | | NULL | |
| SECTOR_MAP_IMG_PATH | char(200) | YES | | NULL | |
+---------------------+-------------+------+-----+---------+----------------+
mysql> show fields from CLIENT;
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| id | int(10) | NO | PRI | NULL | |
| NAME | char(50) | NO | | NULL | |
| DOB | int(8) | NO | | NULL | |
| LOCAL_BRANCH | int(10) | YES | | NULL | |
| FACEBOOK_ID | char(50) | NO | | NULL | |
| START_DATE | int(8) | NO | | NULL | |
| EMAIL | char(50) | YES | | NULL | |
| PIN | int(4) | YES | | NULL | |
| END_DATE | int(8) | NO | | NULL | |
| LEVEL | int(2) | YES | | NULL | |
| TEL | varchar(20) | YES | | NULL | |
+--------------+-------------+------+-----+---------+-------+
mysql> show fields from CLASS_DETAIL;
+--------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+-------+
| id | int(10) | NO | PRI | NULL | |
| NAME | char(50) | NO | | NULL | |
| DESCRIPTION | char(200) | NO | | NULL | |
| CATEGORY | varchar(4) | YES | | NULL | |
| ACHIEVE_TYPE | char(200) | YES | | NULL | |
| IMG_M | varchar(200) | YES | | NULL | |
| IMG_F | varchar(200) | YES | | NULL | |
+--------------+--------------+------+-----+---------+-------+
mysql> show fields from CLASS;
+-----------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| CLASS_ID | int(10) | YES | | NULL | |
| BRANCH_ID | int(10) | NO | | NULL | |
| DURATION | int(3) | YES | | NULL | |
| DATE | date | NO | | NULL | |
| TIME | time | NO | | NULL | |
| STATUS | char(1) | NO | | NULL | |
+-----------+---------+------+-----+---------+----------------+
7 rows in set (0.11 sec)

Need a SQL command for these tables

I have the following 2 tables (student and attendance):
mysql> describe student;
+----------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+----------------+
| student_id | int(11) | NO | PRI | NULL | auto_increment |
| student_email | varchar(255) | YES | | NULL | |
| student_phone_number | varchar(255) | YES | | NULL | |
| parent_first_name | varchar(255) | NO | | NULL | |
| parent_last_name | varchar(255) | NO | | NULL | |
| parent_email | varchar(255) | NO | | NULL | |
| parent_phone_number | varchar(255) | NO | | NULL | |
| first_name | varchar(255) | NO | | NULL | |
| last_name | varchar(255) | NO | | NULL | |
| days_absent | int(11) | YES | | NULL | |
| days_tardy | int(11) | YES | | NULL | |
| class_id | int(11) | NO | MUL | NULL | |
+----------------------+--------------+------+-----+---------+----------------+
mysql> describe attendance;
+-----------------+------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------+------+-----+---------+-------+
| student_id | int(11) | NO | PRI | NULL | |
| class_id | int(11) | NO | PRI | NULL | |
| attendance_date | date | NO | PRI | NULL | |
| absent | tinyint(1) | YES | | NULL | |
| tardy | tinyint(1) | YES | | NULL | |
| note | text | YES | | NULL | |
+-----------------+------------+------+-----+---------+-------+
I want to check the attendance and email of all the children who are absent or tardy for the day. Is there a SQL statement I can use that can, for example, select the students from attendance with an absent/tardy value = 1, then using that student_id specified in the attendance table, pull all the student info from the student table where attendance.student_id = student.student_id?
just try exists
select student_email,student_phone_number from student std
where exists(
select 1 from attendance atd where std.student_id = atd.student_id
and (atd.absent =1 or atd.tardy =1)
)
just make sure you select all the info from student table and exists all the filter in attendance talbe. the condition is student_id.
Also if you need info from attendance talbe, then use join.

Complex MySQL Join with 3 tables and many2many relations

I have 3 tables person, account and subscription. Account belongs to Person as one to many and Account and Subscription are many to many.I need a sql which can select data from three tables.-
Person Tables
+----------------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(128) | NO | | NULL | |
| password | varchar(128) | NO | | NULL | |
| account_id | int(11) | NO | | NULL | |
+----------------------------+---------------+------+---------------+----------------+
Account table
+--------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| yearly_renew | tinyint(1) | NO | | NULL | |
| date_joined | date | NO | | NULL | |
| last_renewed | datetime | YES | | NULL | |
| signup | tinyint(1) | NO | | NULL | |
| reason | varchar(100) | YES | | NULL | |
| yearly_total | int(11) | YES | | NULL | |
| total | int(11) | YES | | NULL | |
+--------------+--------------+------+-----+---------+----------------+
Account-Subscription table
+-----------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| account_id | int(11) | NO | MUL | NULL | |
| subscription_id | int(11) | NO | MUL | NULL | |
+-----------------+---------+------+-----+---------+----------------+
Subscription table
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| subscription_type | varchar(150) | YES | | NULL | |
| hold | tinyint(1) | NO | | NULL | |
| start_date | date | YES | | NULL | |
| end_date | date | YES | | NULL | |
| amount_paid | double | YES | | NULL | |
| date_paid | date | YES | | NULL | |
| transaction_id | int(11) | YES | | NULL | |
| free | tinyint(1) | NO | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
Expecting output in a single query -
OUTPUT
+-----------+------------+--------------+
| person.id | account.id | subscription.id |
+-----------+------------+--------------+
| 10 | 11 | 20 |
| 15 | 32 | 45 |
| 23 | 43 | null |
+--------+---------+-----------------+
try this. it may works properly...
SELECT p.Id AS person.id
,p.account_id AS account.id
,acsub.subscription_id as subscription.id
FROM Person AS p
LEFT JOIN Account-Subscription AS acsub ON p.account_id=acsub.account_id
SELECT p.Id AS person.id
,p.account_id AS account.id
,acsub.subscription_id as subscription.id
FROM Person AS p
INNER JOIN
Account-Subscription AS acsub ON p.account_id=acsub.account_id

MySQL : why is left join slower then inner join? Optimization help required

I have a MySQL query which joins between the two table. I need to map call id from first table with second table. Second table may not have the call id, hence I need to left join the tables. Below is the query, it takes around 125 seconds to finish.
select uniqueid, TRANTAB.DISP, TRANTAB.DIAL FROM
closer_log LEFT JOIN
(select call_uniqueId, sum(dispo_duration) as DISP, sum(dialing_duration) as DIAL
from agent_transition_log group by call_uniqueId) TRANTAB
on closer_log.uniqueid=TRANTAB.call_uniqueId;
Here is the explain output of the query with left join.
+----+-------------+----------------------+-------+---------------+----------------------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+---------------+----------------------------+---------+------+--------+-------------+
| 1 | PRIMARY | closer_log | index | NULL | uniqueid | 43 | NULL | 37409 | Using index |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 32535 | |
| 2 | DERIVED | agent_transition_log | index | NULL | index_agent_transition_log | 43 | NULL | 159406 | |
+----+-------------+----------------------+-------+---------------+----------------------------+---------+------+--------+-------------+
If I do the internal join, then execution time is around 2 seconds.
select uniqueid, TRANTAB.DISP, TRANTAB.DIAL FROM
closer_log JOIN
(select call_uniqueId, sum(dispo_duration) as DISP, sum(dialing_duration) as DIAL
from agent_transition_log group by call_uniqueId) TRANTAB
on closer_log.uniqueid=TRANTAB.call_uniqueId;
Explain output of query with internal join.
+----+-------------+----------------------+-------+------------------------------------+----------------------------+---------+-----------------------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+------------------------------------+----------------------------+---------+-----------------------+--------+--------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 32535 | |
| 1 | PRIMARY | closer_log | ref | uniqueid,index_closer_log | index_closer_log | 43 | TRANTAB.call_uniqueId | 1 | Using where; Using index |
| 2 | DERIVED | agent_transition_log | index | NULL | index_agent_transition_log | 43 | NULL | 159406 | |
+----+-------------+----------------------+-------+------------------------------------+----------------------------+---------+-----------------------+--------+--------------------------+
My question is, why is internal join so much faster then left join. Does my query has any logical fault which is causing the slow execution? What are my optimization options. The call ids in both the tables are indexed.
Edit 1) Added table descriptions
mysql> desc agent_transition_log;
+--------------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+----------------------+------+-----+---------+-------+
| user_log_id | int(9) unsigned | NO | MUL | NULL | |
| event_time | datetime | YES | | NULL | |
| dispoStatus | varchar(6) | YES | | NULL | |
| call_uniqueId | varchar(40) | YES | MUL | NULL | |
| xfer_call_uid | varchar(40) | YES | | NULL | |
| pause_duration | smallint(5) unsigned | YES | | 0 | |
| wait_duration | smallint(5) unsigned | YES | | 0 | |
| dialing_duration | smallint(5) unsigned | YES | | 0 | |
| ring_wait_duration | smallint(5) unsigned | YES | | 0 | |
| talk_duration | smallint(5) unsigned | YES | | 0 | |
| dispo_duration | smallint(5) unsigned | YES | | 0 | |
| park_duration | smallint(5) unsigned | YES | | 0 | |
| rec_duration | smallint(5) unsigned | YES | | 0 | |
| xfer_wait_duration | smallint(5) unsigned | YES | | 0 | |
| logged_in_duration | smallint(5) unsigned | YES | | 0 | |
| sub_status | varchar(6) | YES | | NULL | |
+--------------------+----------------------+------+-----+---------+-------+
16 rows in set (0.00 sec)
mysql> desc closer_log;
+----------------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+----------------------+------+-----+---------+----------------+
| closecallid | int(9) unsigned | NO | PRI | NULL | auto_increment |
| lead_id | int(9) unsigned | NO | MUL | NULL | |
| list_id | bigint(14) unsigned | YES | | NULL | |
| campaign_id | varchar(20) | YES | MUL | NULL | |
| call_date | datetime | YES | MUL | NULL | |
| start_epoch | int(10) unsigned | YES | | NULL | |
| end_epoch | int(10) unsigned | YES | | NULL | |
| length_in_sec | int(10) | YES | | NULL | |
| status | varchar(6) | YES | | NULL | |
| phone_code | varchar(10) | YES | | NULL | |
| phone_number | varchar(18) | YES | MUL | NULL | |
| user | varchar(20) | YES | | NULL | |
| comments | varchar(255) | YES | | NULL | |
| processed | enum('Y','N') | YES | | NULL | |
| queue_seconds | decimal(7,2) | YES | | 0.00 | |
| user_group | varchar(20) | YES | | NULL | |
| xfercallid | int(9) unsigned | YES | | NULL | |
| uniqueid | varchar(40) | YES | MUL | NULL | |
| callerid | varchar(40) | YES | | NULL | |
| agent_only | varchar(20) | YES | | | |
| queue_position | smallint(4) unsigned | YES | | 1 | |
| root_uid | varchar(40) | YES | | NULL | |
| parent_uid | varchar(40) | YES | | NULL | |
| extension | varchar(100) | YES | | NULL | |
| alt_dial | varchar(6) | YES | | NULL | |
| talk_duration | smallint(5) unsigned | YES | | 0 | |
| did_pattern | varchar(50) | YES | | NULL | |
+----------------+----------------------+------+-----+---------+----------------+
Left join looks for the fields from left + unmatched entries from right, so it has to check every joined field in the right table which might be NULL (if you don't have an index on the fields for that JOIN, it means the query will check the whole right table every time). Inner join looks only for direct matches, so it might not have to go over the whole table to perform a join (Especially if you join on indexed fields).
By the way, if you only want to display the entries mentioned in agent_transition_log, you don't need join at all:
select call_uniqueId, sum(dispo_duration) as DISP, sum(dialing_duration) as DIAL
from agent_transition_log group by call_uniqueId;
will do the job.
OR if you do want to add the missing entries:
SELECT call_uniqueId, sum(dispo_duration) as DISP, sum(dialing_duration) as DIAL
from agent_transition_log group by call_uniqueId
UNION
SELECT uniqueid as call_uniqueid, NULL as DISP, NULL as DIAL from closer_log
WHERE uniqueid not in (SELECT call_uniqueid FROM agent_transition_log);