greatest n per group with a 3 tables join
-
05-01-2021 - |
Question
Working on a project with following objects:
People
- id
Vehicles
- id
- model: text
and a link table for owners which passes through owners changes
Owner_Changes
- old_person_id
- new_person_id
- vehicle_id
- date
I'm trying to get a vehicle owner (People->OwnerChanges->Vehicles, and the only way to achieve that is to get the latest owner change by date.
I'm trying to join People/OwnerChanges/Vehicles with following query and get always the old vehicles associated with people
SELECT `people`.`id`, `people`.`name`, `people`.`surname`, `people`.`email`,
`people`.`city`, `people`.`receives_news` , `vehicles`.`model`,
`vehicles`.`id`, `owner_changes`.`date`
FROM `bm_prod`.`people`
INNER JOIN
( SELECT vehicle_id, new_person_id, date, MAX(date) maxDate
FROM owner_changes
GROUP BY id
) owner_changes ON `owner_changes`.`new_person_id` = `people`.`id`
AND `owner_changes`.`date` = `owner_changes`.`maxDate`
INNER JOIN `bm_prod`.`vehicles` ON (`owner_changes`.`vehicle_id`
= `vehicles`.`id`)
WHERE `receives_news` = '1'
AND NOT (`email` = '')
AND `people`.`receives_news` = '1'
AND LOWER(`vehicles`.`model`) LIKE '%mts%'
ORDER BY `vehicles`.`id` ASC, `owner_changes`.`date` DESC
LIMIT 200
Ids 23
and 111
are examples of duplicates I'd like to choose the latest by date (DESC):
Any help or documentation about greatest-n-per-group with 3 tables will be most appreciated.
Create table statement is following:
CREATE TABLE `people` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`surname` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`birthdate` date DEFAULT NULL,
`email` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`phone_number` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`fax_number` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`mobile_number` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'Mobile Number',
`address` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`street_number` varchar(255) DEFAULT NULL,
`zipcode` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`city` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`country` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`company` varchar(255) NOT NULL COMMENT 'Company working in',
`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
`comment` text CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT 'a comment on person',
`receives_news` tinyint(1) NOT NULL DEFAULT '1',
`enumerate_id` int(11) NOT NULL COMMENT 'person_category_id',
`driving_license_type_enumerate_id` int(11) DEFAULT NULL COMMENT 'enumerate_id',
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=3299 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
CREATE TABLE `vehicles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`provider_id` int(11) NOT NULL,
`model` varchar(255) COLLATE utf8_bin NOT NULL,
`displacement` int(11) DEFAULT NULL COMMENT 'Cylindrée',
`type_reception` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Reception_par_type',
`km` bigint(20) DEFAULT NULL,
`first_use` date DEFAULT NULL,
`color` varchar(255) COLLATE utf8_bin NOT NULL,
`enumerate_id` int(11) DEFAULT NULL COMMENT 'reference to enumerate->vehicle_usage_type',
`chassis_number` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Numéro de chassis',
`plate_number` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Numéro de plaque',
`vehicle_type_id` int(11) NOT NULL,
`warranty` varchar(255) COLLATE utf8_bin DEFAULT NULL COMMENT 'Warranty',
`production_year` int(11) DEFAULT NULL,
`comment` mediumtext COLLATE utf8_bin,
`created` datetime NOT NULL,
`modified` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1792 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
CREATE TABLE `owner_changes` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'identifier',
`vehicle_id` int(11) NOT NULL,
`new_person_id` int(11) DEFAULT NULL,
`old_person_id` int(11) DEFAULT NULL,
`buy_price` float DEFAULT NULL,
`sell_price` float DEFAULT NULL,
`date` date DEFAULT NULL,
`km` bigint(20) DEFAULT NULL,
`comment` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`created` datetime DEFAULT NULL,
`modified` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2336 DEFAULT CHARSET=utf8 COLLATE=utf8_bin
Version: MariaDB 10.1:
pg@vmDebDev1: ~$ mysql --version mysql Ver 15.1 Distrib 10.1.26-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2
Solution
Any help or documentation about greatest-n-per-group with 3 tables will be most appreciated.
Source data tables:
create table people (id int, name text)
select 1 id, 'John' name union all
select 2 , 'Mark' union all
select 3 , 'Igor';
create table vehicles (id int, model text)
select 11 id,'digger' model union all
select 12 ,'crane';
create table ownerchanges (old_person_id int, new_person_id int, vehicle_id int, cdate date)
select null old_person_id, 1 new_person_id, 11 vehicle_id, '2018-01-01' cdate union all
select 1 , 3 , 11 , '2018-01-02' union all
select 3 , 2 , 11 , '2018-01-03' union all
select null , 1 , 12 , '2018-01-01' union all
select 1 , 3 , 12 , '2018-01-02' ;
Query:
select v.id, v.model, p.id, p.name
from vehicles v,
people p,
ownerchanges o,
(select oc.vehicle_id, max(oc.cdate) maxdate -- select max date
from ownerchanges oc -- of owner change
group by oc.vehicle_id) last -- for each vehicle
where o.vehicle_id = last.vehicle_id -- use it to select
and o.cdate = last.maxdate -- proper change record
and o.vehicle_id = v.id -- and attach data
and o.new_person_id = p.id; -- we need
UPDATE WITH JOINS
Please write with JOIN...ON instead of commajoin. – Rick James
This, of course, will reduce visibility, but if you want...
select v.id, v.model, p.id, p.name
from ownerchanges o
join people p on o.new_person_id = p.id
join vehicles v on o.vehicle_id = v.id
join (select oc.vehicle_id, max(oc.cdate) maxdate
from ownerchanges oc
group by oc.vehicle_id) last on o.vehicle_id = last.vehicle_id
and o.cdate = last.maxdate