MySQL: Find "last modified" date from two tables - mysql

I have two MySQL tables: tech_requests and comments. I want to display each tech_request one time in a list ordered by the "last modified" date, whether that be the date of the tech_request creation or the latest comment tied to that tech_request. I was trying to use UNION but I got stuck. Any ideas would be much appreciated. Here are the tables:
CREATE TABLE `tech_requests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`staff_member_id` int(3) NOT NULL,
`date_time` datetime NOT NULL,
`request` text NOT NULL,
`building_id` int(2) NOT NULL,
`technician_id` int(2) DEFAULT NULL,
`completed` tinyint(1) NOT NULL,
`subject` varchar(30) NOT NULL DEFAULT '',
`category_id` int(2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=203 DEFAULT CHARSET=utf8;
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tech_request_id` int(11) NOT NULL,
`technician_id` int(2) NOT NULL,
`date_time` datetime NOT NULL,
`comment` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=234 DEFAULT CHARSET=utf8;

Are you looking for something like this?
SELECT r.id, r.staff_member_id, ...,
GREATEST(r.date_time, COALESCE(c.date_time, 0)) last_modified
FROM tech_requests r LEFT JOIN
(
SELECT tech_request_id, MAX(date_time) date_time
FROM comments c
GROUP BY tech_request_id
) c
ON r.id = c.tech_request_id
ORDER BY last_modified
Here is SQLFiddle demo

Related

MySql Using filesort when i using a group by

I have a little problem with optimizing a query, I have 2 tables, one which records the participation (participation) in a quiz, and the other which records the answer to each question (participation_rep), participation is linked to the campaign table.
SELECT count(DISTINCT p.id) as number_of_participation
FROM participation_rep prep
INNER JOIN participation p
ON p.id = prep.id_participation
AND p.trash <> 1
WHERE prep.id_question IN (780,787,794,801,809)
AND prep.trash <> 1
GROUP BY pp.id_campaign
Explain of the query
And the problem is that this request is very heavy to execute when there is a lot of data which is concerned by the request and I do not know how to optimize it.
This query take 30-50ms to execute.
Structure of table participation :
CREATE TABLE IF NOT EXISTS `participation` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_campagne` int(11) NOT NULL,
`id_identifiant` int(11) DEFAULT NULL,
`firstname` varchar(255) DEFAULT NULL,
`surname` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`date_p` date NOT NULL,
`hour_p` time NOT NULL,
`comment` text,
`trash` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Structure of table participation_rep :
CREATE TABLE IF NOT EXISTS `participation_rep` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_participation` int(11) NOT NULL,
`id_question` int(11) NOT NULL,
`id_rep` int(11) NOT NULL,
`trash` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `id_participation` (`id_participation`,`id_question`,`id_reponse`),
KEY `id_question` (`id_question`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

select from two tables each with different join

Trying to run this query will not return any error but I guess there is still something wrong in it. After four minutes running it keeps elaborating:
SELECT DISTINCT azioni_row.id_az, sofferenze.Descrizione, COUNT(crediti.stato = 'aperta') as aperti, COUNT(crediti.stato = 'chiusa') as chiusi
FROM (`azioni_row`, sofferenze)
JOIN crediti ON azioni_row.id_cred=crediti.id_cre
JOIN azioni_head as ah1 ON azioni_row.id_az=ah1.id_az
JOIN azioni_head as ah2 ON ah2.id_soff = sofferenze.id_soff
GROUP BY id_az
ORDER BY `azioni_row`.`id_az` ASC
If I remove sofferenze.Descrizione from the select list and sofferenze from the FROM list it runs in a few seconds:
SELECT DISTINCT azioni_row.id_az, COUNT(crediti.stato = 'aperta') as aperti, COUNT(crediti.stato = 'chiusa') as chiusi
FROM azioni_row
JOIN crediti ON azioni_row.id_cred=crediti.id_cre
JOIN azioni_head as ah1 ON azioni_row.id_az=ah1.id_az
GROUP BY id_az
ORDER BY `azioni_row`.`id_az` ASC
I would like to show the Descrizione field but the link for it is in the head table, not in the row one. The relationship between head and row is a one to many. I store in head all the info that is not necessary to repeat for each row and the link with Descrizione is one of these fields.
EDIT:
this is the explain:
this is the create for azioni_head:
CREATE TABLE `azioni_head` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tipo` varchar(2) NOT NULL,
`id_az` varchar(11) NOT NULL,
`id_soff` varchar(11) NOT NULL,
`id_soff_gar` varchar(11) DEFAULT NULL,
`date_from` date NOT NULL,
`date_to` date NOT NULL,
`close_why` int(11) NOT NULL,
`RGE` varchar(30) NOT NULL,
`procedente` varchar(2) NOT NULL,
`curatore` varchar(11) NOT NULL,
`legale` varchar(11) NOT NULL,
`tribunale` varchar(11) NOT NULL,
`riparto` varchar(2) NOT NULL DEFAULT '0',
`perc_worst` decimal(13,10) NOT NULL,
`perc_best` decimal(13,10) NOT NULL,
`perc_poster` decimal(13,10) NOT NULL,
`attivo_storico` decimal(65,2) NOT NULL,
`passivo_storico` decimal(65,2) NOT NULL,
`attivo_storico_comm` decimal(65,2) NOT NULL,
`passivo_storico_comm` decimal(65,2) NOT NULL,
`acconti` decimal(65,2) NOT NULL,
`acconti_comm` decimal(65,2) NOT NULL,
`numero_comm` int(11) NOT NULL,
`legali_worst` decimal(65,2) NOT NULL,
`legali_best` decimal(65,2) NOT NULL,
`manuale` tinyint(1) NOT NULL DEFAULT '0',
`created_by` int(11) NOT NULL,
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1449 DEFAULT CHARSET=utf8 COMMENT='tabella testata azioni'
this for azioni_row:
CREATE TABLE `azioni_row` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_az` varchar(11) NOT NULL,
`id_cred` varchar(11) NOT NULL,
`chiesto` decimal(65,2) NOT NULL,
`ammesso` decimal(65,2) NOT NULL,
`data_ammesso` date NOT NULL,
`rango_ammesso` tinytext NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4479 DEFAULT CHARSET=utf8
and this for sofferenze
CREATE TABLE `sofferenze` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`id_soff` varchar(11) NOT NULL,
`Descrizione` tinytext NOT NULL,
`gruppo` int(11) NOT NULL,
`cointestazione` int(11) NOT NULL,
`port_man` tinytext NOT NULL,
`head_port_man` tinytext NOT NULL,
`note` longtext NOT NULL,
`created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`created_by` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`),
UNIQUE KEY `id_3` (`id`),
KEY `id_2` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1716 DEFAULT CHARSET=utf8
Please provide proper CREATE statements as well as the output of:
EXPLAIN
SELECT a.id_az
, s.Descrizione
, COUNT(c.stato = 'aperta') aperti
, COUNT(c.stato = 'chiusa') chiusi
FROM azioni_row a
JOIN sofferenze s
CROSS
JOIN crediti c
ON c.id_cre = a.id_cred
JOIN azioni_head ah1
ON ah1.id_az = a.id_az
JOIN azioni_head ah2
ON ah2.id_soff = s.id_soff
GROUP
BY a.id_az
, s.Descrizione
ORDER
BY a.id_az ASC
Edit: You seem to have lots of indexes on the same column. Drop all indexes except the PRIMARY KEYs, and create the following indexes:
sofferenze: id_soff
azioni_row: try a composite index on (id_az,id_cred)
azioni_head: an index on id_soff and an index on id_az
Crediti is missing so I can't comment on that one.

Spped up MySQL query

I need help speeding up a MySQL query that's running extremely slowly. It's taking over 35 seconds to return 900 rows.
Does anyone have ideas how I can speed things up on this query?
Many thanks in advance
select products.*,
p.price as lowest_price,
products_images.thumbnail
from products
inner join products_categories on products_categories.product_id = products.id
inner join products_colours on products_colours.product_id = products.id
inner join products_quantity_pricing on products_quantity_pricing.product_id = products.id
left join ( select min(price) as price, product_id from products_quantity_pricing group by products_quantity_pricing.product_id ) as p on p.product_id = products.id
inner join products_images on products_images.product_id = products.id
where products.id > 0 group by products.id
order by products.product_name
Here is the setup of the tables involved:
CREATE TABLE IF NOT EXISTS `products_categories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` smallint(5) unsigned zerofill NOT NULL,
`category` int(11) NOT NULL,
`sub_category` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1016 ;
CREATE TABLE IF NOT EXISTS `products` (
`product_prefix` varchar(10) NOT NULL,
`id` smallint(5) unsigned zerofill NOT NULL AUTO_INCREMENT,
`supplier_id` int(11) NOT NULL,
`product_code` varchar(50) NOT NULL,
`supplier_product_code` mediumtext NOT NULL,
`product_name` varchar(200) NOT NULL,
`product_description` text NOT NULL,
`print_area` varchar(100) DEFAULT NULL,
`print_position` varchar(100) DEFAULT NULL,
`dimensions` varchar(100) DEFAULT NULL,
`origination` tinytext,
`unit_cost` decimal(9,2) NOT NULL,
`updated` datetime NOT NULL,
`url` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `product_code` (`product_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=901 ;
CREATE TABLE IF NOT EXISTS `products_images` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` smallint(5) unsigned zerofill NOT NULL,
`fullsize` varchar(255) NOT NULL,
`midsize` varchar(255) NOT NULL,
`thumbnail` varchar(255) NOT NULL,
`updated` datetime NOT NULL,
`colour_tag` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2402 ;
CREATE TABLE IF NOT EXISTS `products_colours` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_id` smallint(5) unsigned zerofill NOT NULL,
`colour` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `product_id` (`product_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=2546 ;
CREATE TABLE IF NOT EXISTS `products_quantity_pricing` (
`product_id` smallint(5) unsigned zerofill NOT NULL,
`quantity` smallint(6) NOT NULL,
`price` decimal(9,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Add indexes on the product_id columns in all the tables.
In the products_quantity_pricing, a composite index on (product_id, price) will also speed up finding the minimum price for each product. If you create this composite index, you don't need to create a separate index just on product_id; the prefix of a composite index also serves as an index of its own.

SQL query; inner join on 4 tables

Is this the most efficient way of joining these 4 tables? Also is it possible to only have some rows of each tables selected? I tried changing * to a name of a column but only the columns from studentlist are allowed.
SELECT c.classID, c.instrument, c.grade, u.ID, u.firstname, u.lastname, u.lastsongplayed, u.title
FROM studentlist s
INNER JOIN classlist c ON s.listID = c.classID
INNER JOIN (
SELECT *
FROM users u
INNER JOIN library l ON u.lastsongplayed = l.fileID
)
u ON s.studentID = u.ID
WHERE teacherID =3
ORDER BY classID
LIMIT 0 , 30
Database structure:
CREATE TABLE IF NOT EXISTS `classlist` (
`classID` int(11) NOT NULL AUTO_INCREMENT,
`teacherID` int(11) NOT NULL,
`instrument` text,
`grade` int(11) DEFAULT NULL,
PRIMARY KEY (`classID`),
KEY `teacherID_2` (`teacherID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=27 ;
CREATE TABLE IF NOT EXISTS `studentlist` (
`listID` int(11) NOT NULL,
`studentID` int(11) NOT NULL,
KEY `teacherID` (`studentID`),
KEY `studentID` (`studentID`),
KEY `listID` (`listID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `users` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`email` varchar(60) NOT NULL,
`password` varchar(60) NOT NULL,
`firstname` text NOT NULL,
`lastname` text NOT NULL,
`sessionID` varchar(60) DEFAULT NULL,
`lastlogin` time DEFAULT NULL,
`registerdate` date NOT NULL,
`isteacher` tinyint(1) DEFAULT NULL,
`isstudent` tinyint(1) DEFAULT NULL,
`iscomposer` tinyint(1) DEFAULT NULL,
`lastsongplayed` int(11) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `ID` (`ID`),
UNIQUE KEY `email` (`email`,`sessionID`),
KEY `ID_2` (`ID`),
KEY `ID_3` (`ID`),
KEY `lastsongplayed` (`lastsongplayed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=63 ;
CREATE TABLE IF NOT EXISTS `library` (
`fileID` int(11) NOT NULL AUTO_INCREMENT,
`userID` int(11) NOT NULL,
`uploaddate` datetime NOT NULL,
`title` varchar(60) NOT NULL,
`OrigComposer` varchar(60) NOT NULL,
`composer` varchar(60) NOT NULL,
`genre` varchar(60) DEFAULT NULL,
`year` year(4) DEFAULT NULL,
`arrangement` varchar(60) DEFAULT NULL,
PRIMARY KEY (`fileID`),
KEY `userID` (`userID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=77 ;
Is this the most efficient way of joining these 3 tables?
Your JOIN looks correct and you are joining on your keys. So this should be efficient. However, I would encourage you to analyze your query with EXPLAIN to determine additional optimizations.
Is it possible to only have some rows of each tables selected?
Yes. Change * to be the columns from each table you want. I encourage you to explicitly prefix them with the originating table. Depending on the columns you select, this could also make your query more performant.
SELECT studentlist.studentID, users.email FROM ...

Get same IDs from Detail Table

I have 2 tables in my mysql database:
CREATE TABLE IF NOT EXISTS `RECIPES` (
`recipes_id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(50) COLLATE utf8_bin NOT NULL,
`text` varchar(2000) COLLATE utf8_bin NOT NULL,
`count_persons` int(11) NOT NULL,
`duration` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`date` datetime NOT NULL,
`accepted` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`recipes_id`),
KEY `recipes_user_fk` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=88 ;
CREATE TABLE IF NOT EXISTS `RECIPES_POS` (
`recipes_pos_id` int(11) NOT NULL AUTO_INCREMENT,
`recipes_id` int(11) NOT NULL,
`ingredients_id` int(11) NOT NULL,
`ingredients_value` int(11) NOT NULL,
PRIMARY KEY (`recipes_pos_id`),
KEY `recipe_pos_rec_id` (`recipes_id`),
KEY `recipes_pos_ingredient_fk` (`ingredients_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=58 ;
In the Recipe_Pos Table are many entries. This table shows what ingredients are used in the Recipe.
Now i want to find the recipe which contains incredients like powder and sugar:
SELECT r.recipes_id FROM RECIPES r, RECIPES_POS rp WHERE r.recipes_id = rp.recipes_id AND rp.ingredients_id =6 AND rp.ingredients_id =4
this statment is wrong because a entry in Recipe_Pos can'T contains both incredients.
Whats the right query? It should works with only 1 incredient and more
select r.recipes_id
from RECIPES r
inner join RECIPES_POS rp on r.recipes_id = rp.recipes_id
where rp.ingredients_id in (4, 6)
group by r.recipes_id
having count(distinct rp.ingredients_id) = 2