mysql query using 4 tables to produce small report - mysql

I'm having trouble getting a query to work. 4 tables are used in this query. I want a report looking like this...
Name Success Failure
jdn 5 1
wer 0 3
I want to produce data for the last 24 hours. Here is a sample query I tried and didn't work.
select r.name as jid,
i.id as theid,
(select sum(counter) as scount
from WebServicesIfSummarySuccess
where id=theid
and dtime between date_sub(now(),interval 24 hour) and now()
and sum(counter) >0 and sum(counter) is not null
group by id
) as success,
(select sum(counter) as fcount
from WebServicesIfSummaryFailure
where id=theid
and dtime between date_sub(now(),interval 24 hour) and now()
and sum(counter) >0 and sum(counter) is not null
group by id
) as failure
from router r, interface i
where r.rid = i.rid
and r.name like '%wi%' ;
Here are the table layouts.
router
+-------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+---------------------+------+-----+---------+----------------+
| rid | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | char(120) | NO | MUL | | |
| pop | char(10) | NO | MUL | | |
| popid | tinyint(3) unsigned | NO | | 0 | |
+-------+---------------------+------+-----+---------+----------------+
interface
+-------------+---------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------------+------+-----+---------+----------------+
| id | int(11) unsigned | NO | PRI | NULL | auto_increment |
| name | char(255) | NO | MUL | | |
| rid | int(11) | NO | MUL | 0 | |
| speed | bigint(11) | YES | | NULL | |
| description | char(255) | YES | | NULL | |
| status | enum('active','inactive') | YES | | active | |
+-------------+---------------------------+------+-----+---------+----------------+
Failure and Success are 2 separate tables
+---------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+------------------+------+-----+---------+-------+
| id | int(10) unsigned | NO | PRI | NULL | |
| dtime | datetime | NO | PRI | NULL | |
| counter | bigint(20) | NO | | NULL | |
| rate | int(11) | YES | | NULL | |
+---------+------------------+------+-----+---------+-------+

Related

MySQL stored procedure architecture

I am working on a piece of code that runs a query against MySQL. The syntax is below:
SELECT `order`.`id` AS `id`,
IFNULL(product.main_name, product.name) AS `variant`,
`product`.`id` AS `product_id`,
`product`.`cost` AS `cost`,
ROUND(SUM(order.price), 2) AS `price`,
SUM(order.quantity) AS `quantity`,
`product`.`sku` AS `sku`,
ROUND(order.price/order.quantity, 2) AS `avg_price`,
`product`.`quantity` AS `qty_at_hand`,
`order`.`fulfillment_channel` AS `fulfillment_channel`,
0 as `returns`
FROM `order`
LEFT JOIN `product` ON product.sku = order.sku
WHERE (`order`.`account_id`=1)
AND (`order`.`item_status`<>'Cancelled')
AND (`order`.`purchase_date` >= $start_date)
AND (`order`.`purchase_date` <= $end_date)
GROUP BY `order`.`sku`
My order table:
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
| account_id | int(11) | NO | MUL | NULL | |
| merchant_order_id | varchar(255) | NO | | NULL | |
| purchase_date | datetime | NO | | NULL | |
| updated_date | datetime | NO | | NULL | |
| order_status | varchar(255) | NO | | NULL | |
| product_name | varchar(255) | NO | | NULL | |
| sku | varchar(255) | NO | MUL | NULL | |
| item_status | varchar(255) | NO | | NULL | |
| quantity | int(11) | NO | | NULL | |
| currency | varchar(10) | NO | | NULL | |
| price | decimal(9,2) | YES | | 0.00 | |
| created_at | datetime | NO | | CURRENT_TIMESTAMP | |
| fulfillment_channel | varchar(255) | YES | | NULL | |
My product table:
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
| account_id | int(11) | NO | MUL | NULL | |
| name | varchar(255) | NO | | NULL | |
| main_name | varchar(255) | YES | | NULL | |
| description | text | YES | | NULL | |
| listing_id | varchar(255) | YES | | NULL | |
| sku | varchar(255) | NO | MUL | NULL | |
| open_date | datetime | YES | | NULL | |
| price | decimal(9,2) | NO | | 0.00 | |
| quantity | int(11) | YES | | NULL | |
| supplier_id | int(11) | YES | | NULL | |
| active | tinyint(1) | NO | | 1 | |
| supplier_sku | varchar(255) | YES | | NULL | |
| upc | varchar(255) | YES | | NULL | |
| tag | varchar(255) | YES | | NULL | |
| cost | decimal(9,2) | NO | | 0.00 | |
| ean | int(11) | YES | | NULL | |
| min_order_qty | int(11) | YES | | NULL | |
The query is working fine. However, I would like to replace the QUERY with a stored procedure - a function would take three (3) arguments: start_date, end_date and a boolean flag called full.
I would like the full to be interpreted in a the following way:
- if full is set to false, return the same results query returns now;
- if full is set to true, return a row for each entry in the products table with quantity, price and average price returned as 0, if where fails merged with the query results - a row for each product, whether where were orders in the set period or not.
I was thinking about making a temporary table, then running an update on it and dumping the table after the data has been returned?
What would be the correct way to approach this?
Thank you
Add a UNION to this query and have it do an LEFT OUTER JOIN from Products to Orders table and in the WHERE clause check for full = true and only look for rows with Order.id is NULL. Union would only bring rows when full = true.
Prepare data in SELECT as you specified.

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)

Writing MySQL query with several table joins or multiple select

I am trying to write a MySQL query that gives me results of Organisation Name, its Post Code, any Events that belong to the Organisation and the Post Code of that Event. I've tried all sorts of of join, join and select combinations to no avail. Is this something that is possible ? (I could have a separate table for Org Address and Event Address but it seems like it should be possible to use just one table)
My table structures:
mysql> DESCRIBE cc_organisations;
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| user_id | int(10) unsigned | NO | MUL | NULL | |
| type | enum('C','O') | YES | | NULL | |
| name | varchar(150) | NO | MUL | NULL | |
| description | text | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql> DESCRIBE cc_events;
+-------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| org_id | int(10) unsigned | NO | MUL | NULL | |
| name | varchar(150) | NO | MUL | NULL | |
| start_date | int(11) | NO | MUL | NULL | |
| end_date | int(11) | YES | MUL | NULL | |
| start_time | int(11) | NO | | NULL | |
| end_time | int(11) | NO | | NULL | |
| description | text | YES | | NULL | |
+-------------+------------------+------+-----+---------+----------------+
8 rows in set (0.00 sec)
mysql> DESCRIBE cc_addresses;
+--------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| org_id | int(10) unsigned | YES | MUL | NULL | |
| event_id | int(10) unsigned | YES | MUL | NULL | |
| post_code | varchar(7) | NO | MUL | NULL | |
| address_1 | varchar(100) | NO | | NULL | |
| address_2 | varchar(100) | YES | | NULL | |
| town | varchar(50) | NO | | NULL | |
| county | varchar(50) | NO | | NULL | |
| email | varchar(150) | NO | | NULL | |
| phone | int(11) | YES | | NULL | |
| mobile | int(11) | YES | | NULL | |
| website_uri | varchar(150) | YES | | NULL | |
| facebook_uri | varchar(250) | YES | | NULL | |
| twitter_uri | varchar(250) | YES | | NULL | |
+--------------+------------------+------+-----+---------+----------------+
14 rows in set (0.00 sec)
select o.Name, oAddress.PostCode, e.Name, eAddress.PostCode
from cc_organisations o
inner join cc_addresses oAddress on oAddress.org_id = o.id
left outer join cc_events e on e.org_id=o.id
inner join cc_addresses eAddress on eAddress.event_id = e.id
SELECT cco.name as OrgName, cca.post_code as OrgPostCode, cce.id,
cce.org_id, cce.name, cce.start_date, cce.end_date, cce.start_time,
cce.end_time, cce.description
FROM cc_events cce, cc_addresses cca, cc_organisations cco
WHERE cca.event_id = cce.id AND cco.id=cce.org_id
ORDER BY cce.start_date
LIMIT 50;
You can change your sort and limit, I just added those in because I don't know how big your DB is... You may even be able to get away with:
SELECT cco.name as OrgName, cca.post_code as OrgPostCode, cce.*
FROM cc_events cce, cc_addresses cca, cc_organisations cco
WHERE cca.event_id = cce.id AND cco.id=cce.org_id
ORDER BY cce.start_date LIMIT 50;
But im not 100% sure if the 2nd query will bum out or not.
Your address table has the post codes in it; but it also has an organization id and event id foreign keys. We only need to check the event_id from the address table because any event will belong to an organization.
Address's Event matched Event ID
Event's Organization matched Organization ID

How to make this SQL query faster?

I have the following query:
SELECT DISTINCT `movies_manager_movie`.`id`,
`movies_manager_movie`.`title`,
`movies_manager_movie`.`original_title`,
`movies_manager_movie`.`synopsis`,
`movies_manager_movie`.`keywords`,
`movies_manager_movie`.`release_date`,
`movies_manager_movie`.`rating`,
`movies_manager_movie`.`poster_web_url`,
`movies_manager_movie`.`has_poster`,
`movies_manager_movie`.`number`,
`movies_manager_movie`.`has_sources`,
`movies_manager_movie`.`season_id`,
`movies_manager_movie`.`created`,
`movies_manager_movie`.`updated`,
`movies_manager_moviecache`.`activity_name`
FROM `movies_manager_movie`
LEFT OUTER JOIN `movies_manager_moviecache` ON (`movies_manager_movie`.`id` = `movies_manager_moviecache`.`movie_id`)
WHERE (`movies_manager_movie`.`has_sources` = 1
AND (`movies_manager_moviecache`.`team_member_id` IN (
SELECT U0.`id` FROM `movies_manager_movieteammember` U0
INNER JOIN `movies_manager_movieteammemberactivity` U1 ON (U0.`id` = U1.`team_member_id`)
WHERE U1.`movie_id` = 3588 )
AND `movies_manager_movie`.`number` IS NULL
)
AND NOT (`movies_manager_movie`.`id` = 3588 ))
ORDER BY `movies_manager_moviecache`.`activity_name` DESC LIMIT 3;
This query can take up to 3 seconds and I'm very surprise since I got indexes everywhere and no more than 35 rows in each of my MyIsam tables, using the latest MySQL version.
I cached everything I could but I have at least to run this one 20000 times every day, which is approximately 16 h of waiting for loading. And I'm pretty sure none of my user (nor Google Bot) appreciate a 4 secondes waiting time for each page loading.
What could I do to make it faster ?
I thought about duplicating field from movie to moviecache since the all purpose of movie cache is to denormalize to complex join already.
I tried inlining the subquery to a list of ID but it surprisingly doubled the time of the query.
Tables:
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| title | varchar(120) | NO | UNI | NULL | |
| original_title | varchar(120) | YES | | NULL | |
| synopsis | longtext | YES | | NULL | |
| keywords | varchar(120) | YES | | NULL | |
| release_date | date | YES | | NULL | |
| rating | int(11) | NO | | NULL | |
| poster_web_url | varchar(255) | YES | | NULL | |
| has_poster | tinyint(1) | NO | | NULL | |
| number | int(11) | YES | | NULL | |
| season_id | int(11) | YES | MUL | NULL | |
| created | datetime | NO | | NULL | |
| updated | datetime | NO | | NULL | |
| has_sources | tinyint(1) | NO | | NULL | |
+----------------+--------------+------+-----+---------+----------------+
+---------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(120) | NO | UNI | NULL | |
| biography | longtext | YES | | NULL | |
| birth_date | date | YES | | NULL | |
| picture_web_url | varchar(255) | YES | | NULL | |
| allocine_link | varchar(255) | YES | | NULL | |
| created | datetime | NO | | NULL | |
| updated | datetime | NO | | NULL | |
| has_picture | tinyint(1) | NO | | NULL | |
| biography_linkyfied | longtext | YES | | NULL | |
+---------------------+--------------+------+-----+---------+----------------+
+----------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| movie_id | int(11) | NO | MUL | NULL | |
| tag_slug | varchar(100) | YES | MUL | NULL | |
| team_member_id | int(11) | YES | MUL | NULL | |
| cast_rank | int(11) | YES | | NULL | |
| activity_name | varchar(30) | YES | MUL | NULL | |
+----------------+--------------+------+-----+---------+----------------+
Mysql tells me it's a slow query:
# Query_time: 3 Lock_time: 0 Rows_sent: 9 Rows_examined: 454128
Move movies_manager_movieteammemberactivity and movies_manager_movieteammember to your main join statement (so that you're doing a left outer between movies_manager_movie and the inner join product of the other 3 tables). This should speed up your query considerably.
Try this:
SELECT `movies_manager_movie`.`id`,
`movies_manager_movie`.`title`,
`movies_manager_movie`.`original_title`,
`movies_manager_movie`.`synopsis`,
`movies_manager_movie`.`keywords`,
`movies_manager_movie`.`release_date`,
`movies_manager_movie`.`rating`,
`movies_manager_movie`.`poster_web_url`,
`movies_manager_movie`.`has_poster`,
`movies_manager_movie`.`number`,
`movies_manager_movie`.`has_sources`,
`movies_manager_movie`.`season_id`,
`movies_manager_movie`.`created`,
`movies_manager_movie`.`updated`,
(
SELECT `movies_manager_moviecache`.`activity_name`
FROM `movies_manager_moviecache`
WHERE (`movies_manager_movie`.`id` = `movies_manager_moviecache`.`movie_id`
AND (`movies_manager_moviecache`.`team_member_id` IN (
SELECT U0.`id` FROM `movies_manager_movieteammember` U0
INNER JOIN `movies_manager_movieteammemberactivity` U1 ON (U0.`id` = U1.`team_member_id`)
WHERE U1.`movie_id` = 3588 )
AND `movies_manager_movie`.`number` IS NULL
) ) LIMIT 1) AS `activity_name`
FROM `movies_manager_movie`
WHERE (`movies_manager_movie`.`has_sources` = 1
AND NOT (`movies_manager_movie`.`id` = 3588 ))
ORDER BY `activity_name` DESC
LIMIT 3;
Let me know how that performs