Get most recent record from one-to-many relationship - mysql

As I say in the title, having this schema:
CREATE TABLE IF NOT EXISTS `services` (
`id` int(6) unsigned NOT NULL,
`description` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `services` (`id`, `description`) VALUES
('1', 'Water flood from kitchen'),
('2', 'Light switch burnt');
CREATE TABLE IF NOT EXISTS `visits` (
`id` int(6) unsigned NOT NULL,
`date` DATETIME NOT NULL,
`description` varchar(200) NOT NULL,
`worker` varchar(200) NOT NULL,
`services_id` int(6) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `visits` (`id`, `date`, `description`, `worker`, `services_id`) VALUES
('1', '2018-12-10 16:00:00', 'Find and stop leak', 'Thomas', '1'),
('2', '2018-12-11 09:00:00', 'Change broken pipe', 'Bob', '1'),
('3', '2018-12-10 19:00:00', 'Change light switch', 'Alfred', '2'),
('4', '2018-12-11 10:00:00', 'Paint wall blackened by shortcircuit', 'Ryan', '2');
I need to get the most recent visit, date-wise, for each service.
In this example, I would get:
'1', '2018-12-10 16:00:00', 'Find and stop leak', 'Thomas', '1'
'3', '2018-12-10 19:00:00', 'Change light switch', 'Alfred', '2'
How would you do it? I'm struggling to get a solution.
Here's the SQLFiddle:
http://sqlfiddle.com/#!9/3ca219

I would suggest a correlated subquery:
select v.*
from visits v
where v.date = (select max(v2.date)
from visits v2
where v2.services_id = v.services_id
);
With an index on visits(services_id, date), this should be as fast or faster than other approaches.

Related

How to get rows from table doc_val with minimum "val" from table doc_val for each of the doc_id where criteria = 'L'

You have two tables:
1. docs
2. doc_val
Point of focus is table : doc_val , it has doc_id FK from table docs , field critera which will
be our condition.
Mysql schema:
CREATE TABLE IF NOT EXISTS `docs` (
`id` int(6) unsigned NOT NULL,
`rev` int(3) unsigned NOT NULL,
`content` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `doc_val` (
`id` int(6) unsigned NOT NULL,
`doc_id` int(6) unsigned NOT NULL,
`val` int(3) unsigned NOT NULL,
`type` varchar(2) NOT NULL,
`criteria` varchar(2) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `docs` (`id`, `rev`, `content`) VALUES
('1', '1', 'The earth is flat'),
('2', '1', 'One hundred angels can dance on the head of a pin'),
('3', '1', 'The earth is flat and rests on a bull\'s horn'),
('4', '4', 'The earth is like a ball.');
INSERT INTO `doc_val` (`id`, `doc_id`, `val`, `type`, `criteria`) VALUES
('1', '1', 100, 'D', 'L'),
('2', '1', 101, 'D', 'L'),
('3', '1', 80, 'H', 'L'),
('4', '2', 10, 'H', 'S'),
('5', '2', 90, 'H', 'L'),
('6', '3', 100, 'D', 'L'),
('7', '3', 100, 'D', 'L');
expected output:
DECLARE curIds CURSOR FOR SELECT DISTINCT doc_id FROM doc_val;
DECLARE id INT;
CREATE TEMPORARY TABLE temp(id int, doc_id int, val int, type char(1), criteria char(1));
OPEN curIds;
read_loop: LOOP
FETCH curIds INTO id;
INSERT INTO temp
(Select * from doc_val
where val = (select min(val)
from doc_val
where doc_id = id)) AND criteria = 'L'
END LOOP;
SELECT * FROM temp;
Probably there is a syntax error but i hope you caught the idea.

Query to fetch rows with required data if match is present else NULL, multiple tables?

I have the following tables:
CREATE TABLE `db_make` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(24) DEFAULT NULL,
`status` char(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `ams`.`db_make`
(`id`,
`title`,
`status`)
VALUES
('1', 'DELL', '1'), ('2', 'SAMSUNG', '1'), ('3', 'APPLE', '1');
CREATE TABLE `db_category` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(24) DEFAULT NULL,
`status` char(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `ams`.`db_category`
(`id`,
`title`,
`status`)
VALUES
('1', 'LAPTOP', '1'), ('2', 'MOBILE', '1');
CREATE TABLE `db_model` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` char(24) DEFAULT NULL,
`status` char(1) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `ams`.`db_model`
(`id`,
`title`,
`status`)
VALUES
('1', 'INSPIRON', '1'), ('2', 'IPHONE', '1'), ('3', 'MACBOOK', '1'), ('4', 'NOTEBOOK', '1'), ('5', 'GALAXY', '1');
CREATE TABLE `db_items` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`status` char(1) DEFAULT NULL,
`title` text,
`make` int(11) DEFAULT NULL,
`model` int(11) DEFAULT NULL,
`category` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
CREATE TABLE `db_vendoritem` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`vendorid` int(11) DEFAULT NULL,
`category` int(11) DEFAULT NULL,
`make` int(11) DEFAULT NULL,
`model` int(11) DEFAULT NULL,
`item` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
INSERT INTO `ams`.`db_items`
(`id`,
`status`,
`title`,
`make`,
`model`,
`category`,)
VALUES
('1', '1', '5000 Series', '1', '1', '1');
INSERT INTO `ams`.`db_vendoritem`
(`id`,
`vendorid`,
`category`,
`make`,
`model`,
`item`)
VALUES
('1', '1', '1', null, null, null), ('2', '1', '1', '1', null, null), ('3', '1', null, '2', null, null), ('4', '1', null, null, '3', null), ('5', '1', '1', '1', '1', '1');
A Vendor may specialize in a model, make, category or item - any one or any combination of them. In the above data vendor with id - 1 specializes in (excuse the data)
- all DELL products,
- all DELL laptops,
- all laptops,
- all Inspiron laptops
I need a query that prints - vendorid, make title, category title, model title, item title for all rows in db_vendoritem as shown below:
1, DELL, , , ;
1, DELL, LAPTOP, , ;
1, , MOBILE, , ;
1, , , MACBOOK, ;
1, DELL, LAPTOP, INSPIRON, 5000 series;
You have an error in your code.
INSERT INTO `ams`.`db_items`
(`id`,
`status`,
`title`,
`make`,
`model`,
`category`,)
VALUES
('1', '1', '5000 Series', '1', '1', '1');
The comma in category,)
Not 100% sure if that meets your goal, but this query should give you a start
SELECT
db_vendoritem.`id` AS vendoritem_id,
`db_make`.`title` AS make_title,
`db_model`.`title` AS model_title
FROM
`db_vendoritem`
LEFT JOIN
db_make ON db_make.`id` = db_vendoritem.`make`
LEFT JOIN
db_model ON db_model.`id` = db_vendoritem.`model`
You may try below query -
SELECT VI.`vendorid`
,M.`title` `make title`
,C.`title` `category title`
,MO.`title` `model title`
,I.`title` ` item title`
FROM `db_vendoritem` VI
LEFT JOIN `db_items`I ON VI.`item` = I.`id`
LEFT JOIN `db_model`MO ON VI.`model` = MO.`id`
LEFT JOIN `db_category` C ON VI.`category` = C.`id`
LEFT JOIN `db_make` M ON VI.`make` = M.`id`;
Here is he fiddle.

Is there a tool that can export or import an object from the database

The object I am referring to is about a entity in the data model.
For example, these are the tables in my database:
-- ----------------------------
-- student
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`student_no` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`gender` tinyint(1) NOT NULL,
`age` tinyint(3) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `student` VALUES ('1', '19001', 'John', '1', '13');
INSERT INTO `student` VALUES ('2', '19002', 'Mary', '2', '12');
INSERT INTO `student` VALUES ('3', '19003', 'Tom', '1', '13');
-- ----------------------------
-- course
-- ----------------------------
DROP TABLE IF EXISTS `course`;
CREATE TABLE `course` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `course` VALUES ('1', 'C1');
INSERT INTO `course` VALUES ('2', 'C2');
INSERT INTO `course` VALUES ('3', 'C3');
-- ----------------------------
-- score
-- ----------------------------
DROP TABLE IF EXISTS `score`;
CREATE TABLE `score` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`course_id` int(11) NOT NULL,
`student_id` int(11) NOT NULL,
`score` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `score` VALUES ('1', '1', '1', '100');
INSERT INTO `score` VALUES ('2', '1', '2', '96');
INSERT INTO `score` VALUES ('3', '2', '1', '77');
Student entity includes all data associated with it.
I want to export a student entity named Mary, including all of its associated data (courses, scores)
Through the tool, I want to get the output like the following:
1. json like formats:
{
"id": 2,
"student_no": 19002,
"name": "Mary",
"gender": 2,
"age": 12,
"score": [
{
"id": 2,
"course_id": 1,
"student_id": 2,
"score": 96
}
]
}
2. INSERT statments
INSERT INTO `student` (`id`, `student_no`, `name`, `gender`, `age`) VALUES ('2', '19002', 'Mary', '2', '12');
INSERT INTO `score` (`id`, `course_id`, `student_id`, `score`) VALUES ('2', '1', '2', '96');
Any of the above two formats can help achieve my goal.
purpose
The data associated with Mary is the student record and her course score records, so I hope that this tool can help me transfer data from one database to another, or easily delete any associated records about Mary in a database instead of write the SQL statement myself.
Is there such a tool? The tool should be configurable without writing code, to define the tables involved in the entity and the associated fields between them.
Thank you!

MySQL get all the records of related tables from many to many

I have three tables and I need to list all the options along with all the post that have or do not have options, I have actually done it, but I am only showing the posts that have options but those that do not have options do not show them in the list.
The example in SQL Fiddle: http://sqlfiddle.com/#!9/8d27dd/1
If you look at the list, the post with ID 1, has 3 options assigned to it and shows me a fourth row value null, and the post with ID 2, has an option assigned, but I need to show all the other rows with values null of all the existing options in the table[post_options].
Tables:
tabla[ post ] - Save all the main post
tabla[ post_options] - Save all the options of the post
tabla[ post_has_options] - Save all the post that have options
Code of tables:
CREATE TABLE `post` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`id_post_type` tinyint(3) unsigned NOT NULL,
`title` varchar(255) NOT NULL,
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `FK_title_UNIQUE` (`title`) USING BTREE,
KEY `FK_post_post_types` (`id_post_type`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `post` VALUES ('1', '1', 'Title 1', '2018-01-27 14:58:24', '2018-01-27 23:10:00');
INSERT INTO `post` VALUES ('2', '1', 'Title 2', '2018-01-27 14:58:24', '2018-01-27 23:10:00');
INSERT INTO `post` VALUES ('3', '1', 'Title 3', '2018-01-27 14:58:24', '2018-01-27 23:10:00');
INSERT INTO `post` VALUES ('4', '1', 'Title 4', '2018-01-27 14:58:24', '2018-01-27 23:10:00');
CREATE TABLE `post_has_options` (
`id_post` int(10) unsigned NOT NULL,
`id_post_work_type` tinyint(3) unsigned NOT NULL,
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id_post`,`id_post_work_type`),
KEY `id_post_work_type` (`id_post_work_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `post_has_options` VALUES ('1', '1', '2018-01-27 22:00:51', '2018-01-27 22:00:51');
INSERT INTO `post_has_options` VALUES ('1', '2', '2018-01-27 22:00:54', '2018-01-27 22:00:54');
INSERT INTO `post_has_options` VALUES ('1', '3', '2018-01-27 22:00:58', '2018-01-27 22:00:58');
INSERT INTO `post_has_options` VALUES ('2', '2', '2018-01-27 22:45:19', '2018-01-27 22:45:19');
CREATE TABLE `post_options` (
`id` tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL,
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `FK_name_UNIQUE` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `post_options` VALUES ('1', 'Work type 1', '2018-01-27 14:59:30', '2018-01-27 14:59:30');
INSERT INTO `post_options` VALUES ('2', 'Work type 2', '2018-01-27 14:59:30', '2018-01-27 14:59:30');
INSERT INTO `post_options` VALUES ('3', 'Work type 3', '2018-01-27 14:59:30', '2018-01-27 14:59:30');
INSERT INTO `post_options` VALUES ('4', 'Work type 4', '2018-01-27 14:59:30', '2018-01-27 14:59:30');
Query:
SELECT *
FROM post_options P
LEFT JOIN post_has_options PHO ON PHO.id_post_work_type = P.id
I think this is what you want:
SELECT
*
FROM
post AS p
LEFT OUTER JOIN
post_has_options AS pho
ON
p.id = pho.id_post
LEFT OUTER JOIN
post_options AS po
ON
po.id = pho.id_post_work_type
If not, let me know what you need different and I'll edit my answer. If this is what you need, please remember to mark as answered, so people will know you no longer need help.

MySQL query: Updating foreign key with unique Id

I need to link two tables 1-to-1, but the values that are to be compared and linked upon, are not unique.
I cannot find a way. As an example, I added a very simple version.
CREATE TABLE `T1` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
`uniqueT2Id` int(3) unsigned,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `T2` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `T1` (`id`, `cmp`, `uniqueT2Id`) VALUES
('1', '1', NULL),
('2', '1', NULL),
('3', '2', NULL),
('4', '3', NULL),
('5', '1', NULL);
INSERT INTO `T2` (`id`, `cmp`) VALUES
('1', '1'),
('2', '1'),
('3', '1'),
('4', '2'),
('5', '3');
UPDATE T1 SET uniqueT2Id=
(SELECT id FROM T2 WHERE T2.cmp=T1.cmp AND
id NOT IN (SELECT * FROM
(SELECT uniqueT2Id FROM T1 WHERE uniqueT2Id IS NOT NULL) X)
ORDER BY id ASC LIMIT 1);
SELECT * FROM T1;
http://sqlfiddle.com/#!9/3bab7c/2/0
The result is
id cmp uniqueT2Id
1 1 1
2 1 1
3 2 4
4 3 5
5 1 1
I want it to be
id rev uniqueT2Id
1 1 1
2 1 2
3 2 4
4 3 5
5 1 3
In the UPDATE I try to pick an Id that is not already used, but this obviously does not work. Does anyone know a way to do this in MySQL, preferrably without PHP?
I found an answer myself, with variables. It is horrible and requires a dummy field in the table, but it works. I am open for improvements.
CREATE TABLE `T1` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
`uniqueT2Id` int(3) NULL,
`dummy` varchar(200) NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `T2` (
`id` int(6) unsigned NOT NULL,
`cmp` int(3) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `T1` (`id`, `cmp`, `uniqueT2Id`) VALUES
('1', '1', NULL),
('2', '1', NULL),
('3', '2', NULL),
('4', '5', NULL),
('5', '3', NULL),
('6', '1', NULL);
INSERT INTO `T2` (`id`, `cmp`) VALUES
('1', '1'),
('2', '1'),
('3', '1'),
('4', '2'),
('5', '3');
SET #taken = '/' ;
UPDATE T1
SET uniqueT2Id= #new:=
(SELECT id FROM T2 WHERE T2.cmp=T1.cmp AND
INSTR(#taken, CONCAT('/',id,'/')) = 0
ORDER BY id ASC LIMIT 1),
dummy=IF(#new IS NOT NULL,#taken:=CONCAT(#taken, #new, "/"),NULL);
http://sqlfiddle.com/#!9/4a61d/1/0