Selecting Max TimeStamp values for each ID within a Parameterized View - mysql

MySQL version 5.5.49, on Linux Mint (Ubuntu 14.04.1 based)
The people table contains all of a family: Jed, David, Sarah, and Luke. The cars table contains the two cars we own. The CarPeople table contains an entry for each person who rides in a car, and contains keys that associate the personID to the carID. Last is the carData table, which contains the color of a car, a personID of someone who last painted the car, an image of the paint job, a date of the paint job, and a url to see the image.
This is a strange example, but the idea is that only people who are associated with specific car id's can paint or ride in the car. The example data I inserted has Jed (1) and David (2) riding together in car 1, while David (2), Luke (3), and Sarah (4) ride in car 2.
The following query result must be contained in a view, where a parameter is passed in which references the personID:
Show the CarID, ImageURL, and all people that ride with the PersonID, but only for the latest DataEntryTime for each CarID.
My people_concat column isn't outputting correct results, but I can fix that later.
My main issue is I can't figure out how to output the data row for the max dataentrytime for each carid within this view. Changes I have tried result in only one row being outputted, I can't figure out how to do this.
The crucial test query is this:
select c.* from (select #p1:=2 p) parm , carRiderList c;
This does a select from the view with respect to user 2, David. Instead of 5 rows, only two should be outputted, the first of CarID 2, and the first of carID 1.
Running these queries should result in one row, the one containg the highest dataentrytime for the associated personID's:
select c.* from (select #p1:=1 p) parm , carRiderList c;
select c.* from (select #p1:=3 p) parm , carRiderList c;
select c.* from (select #p1:=4 p) parm , carRiderList c;
Thank you!(SQL Code is below)
/* People in the database */
create table People
(
PersonID int(11) not null unique auto_increment,
phoneNumber varchar(30) not null unique,
Name varchar(40) not null unique,
PRIMARY KEY (PersonID)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into People (phoneNumber, Name)
values ("123-456-7891", "Jed"), ("223-456-7891", "David"), ("323-456-7891", "Luke"), ("423-456-7891", "Sarah");
select * from People;
/* Cars */
drop table if exists Cars;
create table Cars
(
CarID int(11) not null unique auto_increment,
PurchaseTime date,
PRIMARY KEY (CarID)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into Cars (PurchaseTime)
values ("2016-1-1"),("2016-1-2");
select * from Cars;
/* CarPerson: Will contain an entry for each person who rides in the car, and can paint it */
drop table if exists CarPerson;
create table CarPerson
(
CarPersonID int(11) not null unique auto_increment,
CarID int(11) not null,
CarRiderID int(11) not null,
PRIMARY KEY (CarPersonID),
FOREIGN KEY (CarID) references Cars(CarID),
FOREIGN KEY (CarRiderID) references People(PersonID)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into CarPerson(CarID, CarRiderID)
values (1, 1), (1, 2), (2, 2), (2, 3), (2, 4);
select * from CarPerson;
/* CarData: Contains CarID, the color was that car was painted, and the person who painted it, as well as a (fake) imageurl */
create table carData
(
DataID int(11) not null unique auto_increment,
CarID int(11) not null,
Color varchar(20),
DataEntryTime date,
PainterID int(11) not null,
ImageURL varchar(255),
PRIMARY KEY (DataID),
FOREIGN KEY (CarID) references Cars(CarID),
FOREIGN KEY (PainterID) references People(PersonID)
)
ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert into carData(CarID, Color, DataEntryTime, PainterID, ImageURL)
values (1, "Blue", "2013-1-1", 1, "http://www.bluecivic.com"),
(1, "Green", "2013-1-2", 3, "http://greencivic.com"),
(2, "Red", "2014-1-3", 4, "http://redford.com"),
(2, "Purple", "2014-1-4", 2, "http://purpleford.com"),
(2, "Black","2014-1-5", 3, "http://blackford.com");
select * from carData;
/* View I am having trouble with */
create function p1() returns INTEGER DETERMINISTIC NO SQL return #p1;
drop view carRiderList;
create view carRiderList as
(select distinct cp.CarID, cd.ImageURL, DataEntryTime, (
select group_concat(Name order by CarID, PersonID = p1())from People p
left join CarPerson cp
on p.PersonID = cp.CarPersonID
where cp.CarID IN (
select distinct(CarID)
from CarPerson cp
where cp.CarPersonID = p1()
limit 1
)
)
as people_concat
from CarPerson cp
left join carData cd
on cd.CarID = cp.CarID
where cp.CarRiderID = p1()) order by DataEntryTime desc;
select c.* from (select #p1:=2 p) parm , carRiderList c;

Related

Why is MYSQL table not showing?

I am practicing making Databases and tables, so I made a database for baseball info containing a table for Teams and Region they are from (not listed to accuracy). The teams show fine, but when I execute command SELECT * FROM region, it shows me all the columns of ID, name, region, but only has a null value. Code below:
CREATE DATABASE baseball;
USE baseball;
CREATE TABLE teams(
id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE region (
id INT NOT NULL AUTO_INCREMENT,
region_name VARCHAR(255),
teams_id INT NOT NULL,
PRIMARY KEY (id),
FOREIGN KEY (teams_id) REFERENCES teams(id)
);
INSERT INTO teams (name)
VALUES ('Yankees'), ('Red Sox'), ('Mets');
SELECT * FROM teams;
INSERT INTO region (region_name, teams_id)
VALUES ('NorthEast', 1),
('Northeast', 2),
('Central', 3),
('West', 4);
SELECT * FROM region;
Also, the names of teams repeat as well the more I mess with it, something is redundant about this. Thanks.

In MySQL check if set of values is equal to the values of another set; don't care about order

I'm checking if 2 foreign ids of a table are equal to 2 foreign keys in another table to the same table, but I don't care about the order of the ids, just that they have the same values.
i.e.
SELECT (1, 2, 3) = (1, 2, 3);
> 1
SELECT (1, 2, 3) = (2, 1, 3);
> 0
I'd like a way so that (1,2,3) matches (2,1,3) as well as (1,3,2) and (2,3,1).
Unfortunately searching for information on this has proved difficult, most advice is "Lists don't exist in MySQL" and searches for sorting, or unordered checking result in various SQL calls that aren't relevant.
Fiddle: https://www.db-fiddle.com/f/eqz27tR9uDMQriDhkwBo2a/0
I deliberately put an event in the table with the participants ordered differently to the participants in not_event, and it's that join,
SELECT * FROM event
JOIN not_event ON (
(event.participant_1_id, event.participant_2_id) =
(not_event.participant_1_id, not_event.participant_2_id));
That's the issue. I don't care what order participant_1_id and participant_2_id are, in either table, so long as they're the same 2.
Rest of code from fiddle,
CREATE TABLE `participant` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key` varchar(15) NOT NULL,
PRIMARY KEY (`id`));
CREATE TABLE `event` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`participant_1_id` int(11) NOT NULL,
`participant_2_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `event_ibfk_1` FOREIGN KEY (`participant_1_id`) REFERENCES `participant` (`id`),
CONSTRAINT `event_ibfk_2` FOREIGN KEY (`participant_2_id`) REFERENCES `participant` (`id`)
);
CREATE TABLE `not_event` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`participant_1_id` int(11) NOT NULL,
`participant_2_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `not_event_ibfk_1` FOREIGN KEY (`participant_1_id`) REFERENCES `participant` (`id`),
CONSTRAINT `not_event_ibfk_2` FOREIGN KEY (`participant_2_id`) REFERENCES `participant` (`id`)
);
INSERT INTO `participant` VALUES (1, 'Team1');
INSERT INTO `participant` VALUES (2, 'Team2');
INSERT INTO `event` VALUES (NULL, 1, 2);
INSERT INTO `not_event` VALUES (NULL, 2, 1);
SELECT (1, 2, 3) = (1, 2, 3);
SELECT (1, 2, 3) = (2, 1, 3);
SELECT * FROM event
JOIN not_event ON (
(event.participant_1_id, event.participant_2_id) =
(not_event.participant_1_id, not_event.participant_2_id));
SELECT * FROM event
JOIN not_event ON (
(event.participant_1_id, event.participant_2_id) =
(not_event.participant_2_id, not_event.participant_1_id));
A few options, none I'm really happy with,
For binary joins, with only 2 fields, using LEAST and GREATEST works, but on more than 2 fields, it wouldn't work,
SELECT * FROM event
JOIN not_event ON (
LEAST(event.participant_1_id, event.participant_2_id) =
LEAST(not_event.participant_1_id, not_event.participant_2_id)
AND
GREATEST(event.participant_1_id, event.participant_2_id) =
GREATEST(not_event.participant_1_id, not_event.participant_2_id));
After that, there seems to be a dreadfully inefficient LENGTH check, with multiple REPLACEs with CONCAT_WS,
SELECT * FROM event
JOIN not_event ON (
1 = LENGTH(REPLACE(REPLACE(
CONCAT_WS(
',', event.participant_1_id, event.participant_2_id),
not_event.participant_1_id, ''), not_event.participant_2_id, ''))
);
But this one sucks, and is unreliable, because "1" would replace "11" with "", "2" replaces "222" with "", etc.
Updated fiddle (with these solutions): https://www.db-fiddle.com/f/eqz27tR9uDMQriDhkwBo2a/1
I've found you can achieve this via 3 different methods. 1 is querying the event and not_event tables, and joining the participant table twice, grouping them together, and running a GROUP BY with HAVING comparing GROUP_CONCATs,
SELECT event.*, not_event.*
FROM event
JOIN participant p1 ON p1.id IN (event.participant_1_id, event.participant_2_id),
not_event
JOIN participant p2 ON p2.id IN (not_event.participant_1_id, not_event.participant_2_id)
GROUP BY event.id, not_event.id
HAVING
GROUP_CONCAT(p1.key ORDER BY p1.key) =
GROUP_CONCAT(p2.key ORDER BY p2.key)
Or by running 2 subqueries that do GROUP_CONCAT on the field that you're interested in joining them on, and then join them afterwards,
SELECT *
FROM (
SELECT GROUP_CONCAT(participant.id ORDER BY participant.id) `key`, event.*
FROM event
JOIN participant ON (participant.id IN (event.participant_1_id, event.participant_2_id))
GROUP BY event.id) _event
JOIN (
SELECT GROUP_CONCAT(participant.id ORDER BY participant.id) `key`, not_event.*
FROM not_event
JOIN participant ON (participant.id IN (not_event.participant_1_id, not_event.participant_2_id))
GROUP BY not_event.id) _not_event
ON _event.key = _not_event.key;
And then the super "direct" or manual way,
SELECT event.*, not_event.*
FROM event, not_event
WHERE
event.participant_1_id IN (not_event.participant_1_id, not_event.participant_2_id) AND
event.participant_2_id IN (not_event.participant_1_id, not_event.participant_2_id) AND
not_event.participant_1_id IN (event.participant_1_id, event.participant_2_id) AND
not_event.participant_2_id IN (event.participant_1_id, event.participant_2_id)
These all join them correctly as wanted.
Updated fiddle:
https://www.db-fiddle.com/f/eqz27tR9uDMQriDhkwBo2a/5
With both solutions, Event(1, 2) correctly joins with NotEvent(2, 1) and nothing else, and Event(2, 3) correctly joins with NotEvent(3, 2) and nothing else.
I still think it's crazy that you have to join a table like this, in this way, rather than just comparing the keys within the table directly, but these work, one way or another.

Using SQL Sub-queries in an INSERT Statement

Here are the two tables created:
CREATE TABLE category_tbl(
id int NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
subcategory varchar(255) NOT NULL,
PRIMARY KEY(id),
CONSTRAINT nameSubcategory UNIQUE KEY(name, subcategory)
) ENGINE=InnoDB;
CREATE TABLE device(
id INT NOT NULL AUTO_INCREMENT,
cid INT DEFAULT NULL,
name VARCHAR(255) NOT NULL,
received DATE,
isbroken BOOLEAN,
PRIMARY KEY(id),
FOREIGN KEY(cid) REFERENCES category_tbl(id)
) ENGINE=InnoDB;
Below is the instruction that was given to me:
-- insert the following devices instances into the device table (you should use a subquery to set up foriegn keys referecnes, no hard coded numbers):
-- cid - reference to name: phone subcategory: maybe a tablet?
-- name - Samsung Atlas
-- received - 1/2/1970
-- isbroken - True
I'm getting errors on the insert statement below from attempting to use a sub-query within an insert statement. How would you solve this issue?
INSERT INTO devices(cid, name, received, isbroken)
VALUES((SELECT id FROM category_tbl WHERE subcategory = 'tablet') , 'Samsung Atlas', 1/2/1970, 'True');
You have different table name in CREATE TABLE and INSERT INTO so just choose one device or devices
When insert date format use the good one like DATE('1970-02-01')
When insert boolean - just TRUE with no qoutes I beleive.
http://sqlfiddle.com/#!9/b7180/1
INSERT INTO devices(cid, name, received, isbroken)
VALUES((SELECT id FROM category_tbl WHERE subcategory = 'tablet') , 'Samsung Atlas', DATE('1970-02-01'), TRUE);
It's not possible to use a SELECT in an INSERT ... VALUES ... statement. The key here is the VALUES keyword. (EDIT: It is actually possible, my bad.)
If you remove the VALUES keyword, you can use the INSERT ... SELECT ... form of the INSERT statement statement.
For example:
INSERT INTO mytable ( a, b, c) SELECT 'a','b','c'
In your case, you could run a query that returns the needed value of the foreign key column, e.g.
SELECT c.id
FROM category_tbl c
WHERE c.name = 'tablet'
ORDER BY c.id
LIMIT 1
If we add some literals in the SELECT list, like this...
SELECT c.id AS `cid`
, 'Samsung Atlas' AS `name`
, '1970-01-02' AS `received`
, 'True' AS `isBroken`
FROM category_tbl c
WHERE c.name = 'tablet'
ORDER BY c.id
LIMIT 1
That will return a "row" that we could insert. Just precede the SELECT with
INSERT INTO device (`cid`, `name`, `received`, `isbroken`)
NOTE: The expressions returned by the SELECT are "lined up" with the columns in the column list by position, not by name. The aliases assigned to the expressions in the SELECT list are arbitrary, they are basically ignored. They could be omitted, but I think having the aliases assigned makes it easier to understand when we run just the SELECT portion.

Getting a Sum and Count from Different Tables

I'm guessing this is too local but I can't figure out a way to make it more general (which might be why I'm not able to find my answer on Google).
We have an application that tracks contacts for our business. These contacts (Contact table) are either contacted through the phone (Contact_Phone table) or through email (Contact_Email). If the user is contacted through the phone an agent keeps track of the total number of seconds (Contact_Phone.totalSeconds). Through a piece of business logic that I have no control over email contacts are treated as one second. A user might be contact through just email, just phone, or both.
I'm trying to generate a report on how long we've spent contacting each user but I can't get the results I expect.
Tables:
CREATE TABLE IF NOT EXISTS `Contact` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `Contact_Email` (
`id` INT NOT NULL AUTO_INCREMENT ,
`ContactId` INT NULL ,
PRIMARY KEY (`id`) ,
INDEX `contact_email_contact_idx` (`ContactId` ASC) ,
CONSTRAINT `contact_email_contact`
FOREIGN KEY (`ContactId` )
REFERENCES `Contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `Contact_Phone` (
`id` INT NOT NULL AUTO_INCREMENT ,
`totalSeconds` INT NULL ,
`ContactId` INT NULL ,
PRIMARY KEY (`id`) ,
INDEX `Contact_Phone_contact_idx` (`ContactId` ASC) ,
CONSTRAINT `Contact_Phone_contact`
FOREIGN KEY (`ContactId` )
REFERENCES `Contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Test Data:
insert into Contact (id, name) values (1, 'Scott');
insert into Contact (id, name) values (2, 'Joe');
insert into Contact_Phone (totalSeconds, ContactId) values (10, 2);
insert into Contact_Phone (totalSeconds, ContactId) values (100, 2);
insert into Contact_Email (ContactId) values (1);
insert into Contact_Email (ContactId) values (1);
insert into Contact_Email (ContactId) values (2);
Query:
select
name,
(select sum(totalSeconds) from Contact_Phone where Contact_Phone.ContactId = Contact.id)
+
(select count(*) from Contact_Email where Contact_Email.ContactId = Contact.id)
from Contact;
Expected Results:
Joe 111
Scott 2
Actual Results:
Joe 111
Scott null
Thanks
How about using summaries and LEFT JOIN operations, like so?
SELECT Contact.name,
COALESCE(p.seconds,0) + COALESCE(e.seconds,0) seconds
FROM Contact.Name
LEFT JOIN (
SELECT ContactID AS id,
SUM(totalSeconds) AS seconds
FROM ContactPhone
GROUP BY ContactID
) p ON Contact.id = p.id
LEFT JOIN (
SELECT ContactID AS id,
COUNT(*) AS seconds
FROM ContactEmail
GROUP BY ContactID
) e ON Contact.id = e.id
The LEFT JOIN operations will preserve your result rows where one or the other of your "seconds" computations is NULL. And, the COALESCE operations will prevent your query from attempting arithmetic on NULL values, which yields NULL.

MySQL using IN/FIND_IN_SET to read multiple rows in sub query

I have two tables, locations and location groups
CREATE TABLE locations (
location_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(63) UNIQUE NOT NULL
);
INSERT INTO locations (name)
VALUES
('london'),
('bristol'),
('exeter');
CREATE TABLE location_groups (
location_group_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
location_ids VARCHAR(255) NOT NULL,
user_ids VARCHAR(255) NOT NULL,
name VARCHAR(63) NOT NULL,
);
INSERT INTO location_groups (location_ids, user_ids, name)
VALUES
('1', '1,2,4', 'south east'),
('2,3', '2', 'south west');
What I am trying to do is return all location_ids for all of the location_groups where the given user_id exists. I'm using CSV to store the location_ids and user_ids in the location_groups table. I know this isn't normalised, but this is how the database is and it's out of my control.
My current query is:
SELECT location_id
FROM locations
WHERE FIND_IN_SET(location_id,
(SELECT location_ids
FROM location_groups
WHERE FIND_IN_SET(2,location_groups.user_ids)) )
Now this works fine if the user_id = 1 for example (as only 1 location_group row is returned), but if i search for user_id = 2, i get an error saying the sub query returns more than 1 row, which is expected as user 2 is in 2 location_groups. I understand why the error is being thrown, i'm trying to work out how to solve it.
To clarify when searching for user_id 1 in location_groups.user_ids the location_id 1 should be returned. When searching for user_id 2 the location_ids 1,2,3 should be returned.
I know this is a complicated query so if anything isn't clear just let me know. Any help would be appreciated! Thank you.
You could use GROUP_CONCAT to combine the location_ids in the subquery.
SELECT location_id
FROM locations
WHERE FIND_IN_SET(location_id,
(SELECT GROUP_CONCAT(location_ids)
FROM location_groups
WHERE FIND_IN_SET(2,location_groups.user_ids)) )
Alternatively, use the problems with writing the query as an example of why normalization is good. Heck, even if you do use this query, it will run more slowly than a query on properly normalized tables; you could use that to show why the tables should be restructured.
For reference (and for other readers), here's what a normalized schema would look like (some additional alterations to the base tables are included).
The compound fields in the location_groups table could simply be separated into additional rows to achieve 1NF, but this wouldn't be in 2NF, as the name column would be dependent on only the location part of the (location, user) candidate key. (Another way of thinking of this is the name is an attribute of the regions, not the relations between regions/groups, locations and users.)
Instead, these columns will be split off into two additional tables for 1NF: one to connect locations and regions, and one to connect users and regions. It may be that the latter should be a relation between users and locations (rather than regions), but that's not the case with the current schema (which could be another problem of the current, non-normalized schema). The region-location relation is one-to-many (since each location is in one region). From the sample data, we see the region-user relation is many-many. The location_groups table then becomes the region table.
-- normalized from `location_groups`
CREATE TABLE regions (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- slightly altered from original
CREATE TABLE locations (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- missing from original sample
CREATE TABLE users (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- normalized from `location_groups`
CREATE TABLE location_regions (
`region` INT UNSIGNED,
`location` INT UNSIGNED UNIQUE NOT NULL,
PRIMARY KEY (`region`, `location`),
FOREIGN KEY (`region`)
REFERENCES regions (id)
ON DELETE restrict ON UPDATE cascade,
FOREIGN KEY (`location`)
REFERENCES locations (id)
ON DELETE cascade ON UPDATE cascade
);
-- normalized from `location_groups`
CREATE TABLE user_regions (
`region` INT UNSIGNED NOT NULL,
`user` INT UNSIGNED NOT NULL,
PRIMARY KEY (`region`, `user`),
FOREIGN KEY (`region`)
REFERENCES regions (id)
ON DELETE restrict ON UPDATE cascade,
FOREIGN KEY (`user`)
REFERENCES users (id)
ON DELETE cascade ON UPDATE cascade
);
Sample data:
INSERT INTO regions
VALUES
('South East'),
('South West'),
('North East'),
('North West');
INSERT INTO locations (`name`)
VALUES
('London'),
('Bristol'),
('Exeter'),
('Hull');
INSERT INTO users (`name`)
VALUES
('Alice'),
('Bob'),
('Carol'),
('Dave'),
('Eve');
------ Location-Region relation ------
-- temporary table used to map natural keys to surrogate keys
CREATE TEMPORARY TABLE loc_rgns (
`location` VARCHAR(63) UNIQUE NOT NULL
`region` VARCHAR(63) NOT NULL,
);
-- Hull added to demonstrate correctness of desired query
INSERT INTO loc_rgns (region, location)
VALUES
('South East', 'London'),
('South West', 'Bristol'),
('South West', 'Exeter'),
('North East', 'Hull');
-- map natural keys to surrogate keys for final relationship
INSERT INTO location_regions (`location`, `region`)
SELECT loc.id, rgn.id
FROM locations AS loc
JOIN loc_rgns AS lr ON loc.name = lr.location
JOIN regions AS rgn ON rgn.name = lr.region;
------ User-Region relation ------
-- temporary table used to map natural keys to surrogate keys
CREATE TEMPORARY TABLE usr_rgns (
`user` INT UNSIGNED NOT NULL,
`region` VARCHAR(63) NOT NULL,
UNIQUE (`user`, `region`)
);
-- user 3 added in order to demonstrate correctness of desired query
INSERT INTO usr_rgns (`user`, `region`)
VALUES
(1, 'South East'),
(2, 'South East'),
(2, 'South West'),
(3, 'North West'),
(4, 'South East');
-- map natural keys to surrogate keys for final relationship
INSERT INTO user_regions (`user`, `region`)
SELECT user, rgn.id
FROM usr_rgns AS ur
JOIN regions AS rgn ON rgn.name = ur.region;
Now, the desired query for the normalized schema:
SELECT DISTINCT loc.id
FROM locations AS loc
JOIN location_regions AS lr ON loc.id = lr.location
JOIN user_regions AS ur ON lr.region = ur.region
;
Result:
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+