multi join mysql query taking too long to execute - mysql

I have 4 tables as below ,i am trying to join these tables but the query is taking too long to execute.Please tell me how do i optimize this.
Trying to do below
1) using a sub query i am creating a table based on input date range
2) i require to group result based on bank then on district and then on state,so that i can filter results on front end as State-->District-->Bank
3) Also i need to avoid some junk data which i am doing using not like clause.
select substring(a.ifsc,1,4) as code,
s.new_state as state,
s.state_id as stid,
d.new_dist as dist,
b.ifbank as bank,
count(a.amt) as num,
sum(a.amt) as amt from
(SELECT * FROM mtr where orgdate between '$fdate_new' and '$tdate_new')
as a JOIN ifsc b on b.ifscd=a.ifsc
JOIN user c on a.excd=c.mtr
JOIN state_mapping s on b.state=s.org_state
JOIN dist_mapping d on b.dist=d.org_dist
where
s.state_id ='$stid' and
TRIM(d.new_dist) <> '' and
d.new_dist IS NOT NULL
group by bank,dist order by amt desc;
dist_mapping table
+----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+-------+
| org_dist | varchar(20) | YES | | NULL | |
| new_dist | varchar(20) | YES | | NULL | |
+----------+-------------+------+-----+---------+-------+
ifsc table
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| ifscd | varchar(11) | NO | PRI | | |
| ifscbr | varchar(40) | YES | | NULL | |
| ifbank | varchar(40) | YES | | NULL | |
| newifsc | varchar(11) | YES | | NULL | |
| dist | varchar(20) | YES | | NULL | |
| state | varchar(20) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
state_mapping table
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| org_state | varchar(20) | YES | | NULL | |
| new_state | varchar(20) | YES | | NULL | |
| state_id | int(2) | YES | | NULL | |
+-----------+-------------+------+-----+---------+-------+
user table
+---------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| excode | int(2) | YES | | NULL | |
| mtr | int(2) | YES | | NULL | |
| exname | varchar(40) | YES | | NULL | |
| country | varchar(10) | YES | | NULL | |
+---------+-------------+------+-----+---------+-------+
mysql> desc mtr;
+---------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------------+------+-----+---------+-------+
| excd | int(2) | NO | PRI | 0 | |
| orgdate | date | YES | | NULL | |
| amt | double(12,2) | YES | | NULL | |
| obank | int(1) | YES | | NULL | |
| brcd | int(5) | YES | | NULL | |
| brname | varchar(40) | YES | | NULL | |
| rname | varchar(40) | YES | | NULL | |
| bname | varchar(40) | YES | | NULL | |
| baddr | varchar(60) | YES | | NULL | |
| mob | varchar(32) | YES | | NULL | |
| ifsc | varchar(12) | YES | | NULL | |
+---------+---------------------+------+-----+---------+-------+

Subquery takes more time compare to join Please try this
select substring(a.ifsc,1,4) as code,
s.new_state as state,
s.state_id as stid,
d.new_dist as dist,
b.ifbank as bank,
count(a.amt) as num,
sum(a.amt) as amt
From mtr as a
JOIN ifsc b on b.ifscd=a.ifsc and orgdate between '$fdate_new' and '$tdate_new'
JOIN user c on a.excd=c.mtr
JOIN state_mapping s on b.state=s.org_state
JOIN dist_mapping d on b.dist=d.org_dist
where
s.state_id ='$stid' and `enter code here`
TRIM(d.new_dist) <> '' and
d.new_dist IS NOT NULL
group by bank,dist order by amt desc;

Related

UPDATE FROM another table value with CASE SUBSTRING and WHERE

I tried to update my main table --> budget with values from item_master table with condition
Here's the table structure
budget :
+-------------------+---------------+------+-----+------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------+------+-----+------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| department | varchar(50) | YES | | NULL | |
| section | varchar(50) | YES | | NULL | |
| budget_id | varchar(50) | NO | | NULL | |
| carmaker | varchar(255) | YES | | NULL | |
| carline | varchar(255) | YES | | NULL | |
| phase | varchar(255) | YES | | NULL | |
| purpose | varchar(50) | YES | | NULL | |
| order_plan | varchar(50) | YES | | NULL | |
| required_date | varchar(50) | YES | | NULL | |
| subgroup | varchar(255) | YES | | NULL | |
| item_desc | varchar(255) | YES | | NULL | |
| item_code | varchar(255) | YES | | NULL | |
| qty | int(11) | YES | | NULL | |
| curr | char(3) | YES | | NULL | |
| price | decimal(20,2) | YES | | NULL | |
| amount_ori | decimal(20,2) | YES | | NULL | |
| amount | decimal(20,2) | YES | | NULL | |
| amount_reduce_ori | decimal(20,2) | NO | | NULL | |
| amount_reduce_usd | decimal(20,2) | NO | | NULL | |
| qty_reduce | decimal(20,2) | NO | | NULL | |
| qty_final | int(11) | YES | | NULL | |
| amount_final | decimal(20,2) | YES | | NULL | |
| status | varchar(50) | YES | | uncommited | |
| source | varchar(50) | YES | | NULL | |
| coa_production | char(7) | YES | | NULL | |
| coa_general | char(7) | YES | | NULL | |
| hfm_cr | char(6) | YES | | NULL | |
| hfm_pl | char(6) | YES | | NULL | |
| update_record | varchar(50) | YES | | NULL | |
| user | varchar(50) | YES | | NULL | |
+-------------------+---------------+------+-----+------------+----------------+
item_master :
+----------------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| subgroup | varchar(255) | NO | | NULL | |
| item_desc | varchar(255) | NO | | NULL | |
| item_code | varchar(255) | NO | | NULL | |
| uom | varchar(255) | NO | | NULL | |
| price | decimal(20,2) | NO | | NULL | |
| coa_production | char(7) | NO | | NULL | |
| coa_general | char(7) | NO | | NULL | |
| hfm_cr | varchar(50) | NO | | NULL | |
| hfm_pl | varchar(50) | NO | | NULL | |
+----------------+---------------+------+-----+---------+----------------+
I'm trying to get coa_production or coa general , depend on purpose field
if the first three (3) characters = 'PRO' then use coa_production, else use coa_general with item_code as the unique string/foreign keys
Here's my current code :
UPDATE budget CASE
WHEN SUBSTR(purpose,1,3) = 'PRO' THEN
SET coa_production = (SELECT coa_production FROM item_master WHERE budget.item_code = item_master.item_code) ELSE
SET coa_general = (SELECT coa_general FROM item_master WHERE budget.item_code = item_master.item_code) END
my goal is when purpose = 'PRO' then the only field that has to be filled is coa_production using the value from item_master table, so does if purpose = 'GEN' then the only field that has to be filled is coa_general
I would express this using an update join:
UPDATE budget b
LEFT JOIN item_master im
ON b.item_code = im.item_code
SET
b.coa_production = CASE WHEN LEFT(b.purpose, 3) = 'PRO' THEN im.coa_production END,
b.coa_general = CASE WHEN LEFT(b.purpose, 3) = 'GEN' THEN im.coa_general END
WHERE
LEFT(b.purpose, 3) IN ('PRO', 'GEN');
Note that a left join (rather than an inner join) is required here, to keep the behavior the same as your original query. Using a left join, a NULL would be assigned to a column which did not find any matching record in the item_master table.

sql query count number of record in a join

I have to extract the list of POS(point of service) from pos table, based on location name:
POS
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| address | varchar(200) | YES | | NULL | |
| country | varchar(45) | YES | | NULL | |
| location | varchar(100) | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
so, it would be something like :
select *
from pos
where location = 'new york';
Now , from the table mission i have to count the number of POS (pos_name), and if this number is greater than a number coming from a subquery, pos register should not be shown.
mission
| id | int(11) | NO | PRI | NULL | auto_increment |
| team_name | varchar(45) | YES | | NULL | |
| team_photo | varchar(255) | YES | | NULL | |
| pos_name | varchar(45) | YES | | NULL | |
| pos_id | int(11) | YES | | NULL | |
| product_category | varchar(45) | YES | | NULL | |
| product_platform | varchar(45) | YES | | NULL | |
| created_by | int(11) | YES | | NULL | |
| judged_by | int(11) | YES | | NULL | |
| selfie_photo | varchar(255) | YES | | NULL | |
| like_score | int(11) | YES | | NULL | |
| star_score | float | YES | | NULL | |
| feedback_recommendation | varchar(2000) | YES | | NULL | |
| created_at | timestamp | YES | | CURRENT_TIMESTAMP | |
| updated_at | timestamp | YES | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| sent_date | timestamp | YES | | NULL | |
| locked | tinyint(1) | YES | | 0 | |
+-------------------------+---------------+------+-----+-------------------+-----------------------------+
so until now i developed following sql query :
SELECT p.id,p.name
FROM missions m join pos p
on m.pos_id = p.id
where p.location = 'new york'
having count(m.pos_name) < (select count(*)
from product_category);
but this part of code
having count(m.pos_name)
should be something like that :
select count(*)
from missions
group by pos_name;
because without group by statement i will recieve a sum of all pos, but i need to check it for a group, not for all of them.
Any suggestion ?
I thing you need the data with group by with condition then try this
SELECT p.id,p.name
FROM missions m join pos p
on m.pos_id = p.id
where p.location = 'new york'
group by m.pos_name
having count(m.pos_name) < (select count(*)
from product_category);
Just add group by m.pos_name it will work.
You can check Here

MySQL select last row of each one user from a list of users in a table

Im trying to select from a Moodle table the last row of each user in a list.
my query is
SELECT *
FROM mdl_logstore_standard_log
WHERE eventname='\\core\\event\\user_enrolment_created'
AND courseid=34
AND relateduserid IN(120,128)
GROUP BY relateduserid;`
and the table that i use is :
MariaDB [****_*****]> describe mdl_logstore_standard_log;
+-------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+----------------+
| id | bigint(10) | NO | PRI | NULL | auto_increment |
| eventname | varchar(255) | NO | | | |
| component | varchar(100) | NO | | | |
| action | varchar(100) | NO | | | |
| target | varchar(100) | NO | | | |
| objecttable | varchar(50) | YES | | NULL | |
| objectid | bigint(10) | YES | | NULL | |
| crud | varchar(1) | NO | | | |
| edulevel | tinyint(1) | NO | | NULL | |
| contextid | bigint(10) | NO | MUL | NULL | |
| contextlevel | bigint(10) | NO | | NULL | |
| contextinstanceid | bigint(10) | NO | | NULL | |
| userid | bigint(10) | NO | MUL | NULL | |
| courseid | bigint(10) | YES | MUL | NULL | |
| relateduserid | bigint(10) | YES | | NULL | |
| anonymous | tinyint(1) | NO | | 0 | |
| other | longtext | YES | | NULL | |
| timecreated | bigint(10) | NO | MUL | NULL | |
| origin | varchar(10) | YES | | NULL | |
| ip | varchar(45) | YES | | NULL | |
| realuserid | bigint(10) | YES | | NULL | |
+-------------------+--------------+------+-----+---------+----------------+
My Problem with this query is that it give me the first row for every userid in list, and i want the last. i tried order by id desc but nothing changed.
You can try this:
SELECT
L.*
FROM mdl_logstore_standard_log L
INNER JOIN
(
SELECT
relateduserid,
MAX(id) AS max_id
FROM mdl_logstore_standard_log
WHERE eventname='\\core\\event\\user_enrolment_created'
AND courseid=34
AND relateduserid IN(120,128)
GROUP BY relateduserid
)AS t
ON L.id = t.max_id
First getting the maximum auto increment id for those relateduserids then making an inner join between mdl_logstore_standard_log and t table would return your expected result.
Try this but i didnt test it
select * from mdl_logstore_standard_log where eventname='\\core\\event\\user_enrolment_created' and courseid=34 and relateduserid IN(120,128) GROUP BY relateduserid ORDER BY id DESC LIMIT 1;

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.