MySQL group_concat problems - mysql

I have multiple tables that I need to concatenate a group of results from. There is 6 tables overall with a index in each matching the primary_key in the initial table.
However, when I execute my query it results in multiple instances of each result being returned for each table. If i select just one record the output is fine. It seems that the query is being ran multiple times per table and all the results are being concatenated together.
SELECT id,
GROUP_CONCAT(tb1.table1) AS tbl1,
GROUP_CONCAT(tb2.table2) AS tbl2,
GROUP_CONCAT(tb3.table3) AS tbl3,
GROUP_CONCAT(tb4.table4) AS tbl4,
GROUP_CONCAT(tb5.table5 )AS tbl5
FROM table t
LEFT OUTER JOIN (
SELECT id, field2
FROM table1
GROUP BY id
) tb1
ON tb1.id = t.id
LEFT OUTER JOIN (
SELECT id, field2
FROM table2
GROUP BY id
) tb2
ON tb2.id = t.id
LEFT OUTER JOIN (
SELECT id, field2
FROM table3
GROUP BY id
) tb3
ON tb3.id = t.id
LEFT OUTER JOIN (
SELECT id, field2
FROM table4
GROUP BY id
) tb4
ON tb4.id = t.id
LEFT OUTER JOIN (
SELECT id, field2
FROM table5
GROUP BY id
) tb5
ON tb5.id = t.id
GROUP BY t.id
I expected/want the results to be.
Primary Key | Field 1 | Field 2 | Field 3 | Field 4 | Field 5
1 | 1, 2 | 2, 3 | 2, 4 | 1, 5 | NUll
But the returned results are, this is only an example of 1 row when not specifying a record id, however all rows appear like this.
Primary Key | Field 1 | Field 2 | Field 3 | Field 4 | Field 5
1 | 1,2 | 2,3, | 2,4 | 1,5, | NUll
2 | 1,2,1, | 2,3,2, | 2,4,2, | 1,5,1, | 1
2 | 1,2,1,2 | 2,3,2,3 | 2,4,2,4 | 1,5,1,5 | 1, 2
I am at a loss where or why the query is iterating over itself multiple times and then iterating over each table.
Any Help would be greatly appreciated.
Regards,
Edit: I have updated my initial desired results and added more rows to how the table is being brought back.
Also included a 4 table schema:
CREATE TABLE IF NOT EXISTS table (
id int(11) NOT NULL AUTO_INCREMENT,
Name varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS `table2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`table1id` int(11) NOT NULL,
`Name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX (`table1id`)
);
CREATE TABLE IF NOT EXISTS `table3` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`table1id` int(11) NOT NULL,
`Name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX (`table1id`)
);
CREATE TABLE IF NOT EXISTS `table4` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`table1id` int(11) NOT NULL,
`Name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX (`table1id`)
);
INSERT INTO `table`(`id`, `Name`) VALUES (1, 'Test'),(2, 'Second Test'),(3,'Third Test'),(4, 'Test Four'),(5,'Test Five');
INSERT INTO `table2` (`id`,`table1id`, `Name`) VALUES (1,1,'Test Value'), (2,2, 'Test Value 2'), (3,3, 'Test Value 3');
INSERT INTO `table3` (`id`,`table1id`, `Name`) VALUES (1,2,'Value'), (2,3, 'Value 2'), (3,4, 'Value 3');
INSERT INTO `table4` (`id`,`table1id`, `Name`) VALUES (1,1,'Test'), (2,2, 'Test 2'), (3,5, 'Test 3');

Use DISTINCT for all columns in GROUP_CONCAT()
Try this:
SELECT t.id,
GROUP_CONCAT(DISTINCT tb1.field2) AS tbl1,
GROUP_CONCAT(DISTINCT tb2.field2) AS tbl2,
GROUP_CONCAT(DISTINCT tb3.field2) AS tbl3,
GROUP_CONCAT(DISTINCT tb4.field2) AS tbl4,
GROUP_CONCAT(DISTINCT tb5.field2) AS tbl5
FROM TABLE t
LEFT OUTER JOIN table1 tb1 ON tb1.id = t.id
LEFT OUTER JOIN table2 tb2 ON tb2.id = t.id
LEFT OUTER JOIN table3 tb3 ON tb3.id = t.id
LEFT OUTER JOIN table4 tb4 ON tb4.id = t.id
LEFT OUTER JOIN table5 tb5 ON tb5.id = t.id
GROUP BY t.id

Related

MySQL inner join with left outer join

I have 4 tables as below.
1. emp
- emp_id
- name
- contact_id
2. contact
- contact_id
- name
3. emp_projects
- prj_id
- emp_id
4. project
- prj_id
- name
Relationships :-
emp to projects - One to Many
I need a query joining all these tables.
Conditions
contact_id column in emp table can be empty so get contact details only if the column is not empty
Employee can be part of Zero or many projects.
Query needs to return the project name as well.
Query that I currently have,
select e.,ep. from emp e left outer join emp_projects ep on e.emp_id = ep.emp_id where e.emp_id=1
Need to join contacts and projects table as well here.
Sample data,
1. emp
| 1 | Mike | 1 |
| 2 | John | - |
2. contact
| 1 | Alex |
3. emp_projects
| 1 | 1 |
| 2 | 1 |
4. projects
| 1 | Test |
| 2 | Mail |
Expected output :-
For emp id 1,
1(emp_id), Mike(emp_name), 1(contact_id), Alex(contact_name), 1(proj_id), Test(Prj_Name)
1(emp_id), Mike(emp_name), 1(contact_id), Alex(contact_name), 2(proj_id), Email(Prj_Name)
For emp id 2, ( Contact column is empty for emp 2 and emp 2 is not associated with any project )
1(emp_id), John(emp_name), -(contact_id), -(contact_name), -(proj_id), -(Prj_Name)
Query and DDL script is added below. 1 recommendation, use the primary key in the mapping table or have a composite key ( emp_id, project_id )
select
employee.id as employee_id,
employee.name as employee_name,
contact.id as contact_id,
contact.name as contact_name,
project.id as project_id,
project.name as project_name
FROM employee employee
LEFT OUTER JOIN contact contact on contact.id = employee.contact_id
LEFT OUTER JOIN employee_projects employee_project on employee_project.employee_id = employee.id
LEFT OUTER JOIN project project on project.id = employee_project.project_id
CREATE TABLE IF NOT EXISTS `employee`
( `id` int(6) unsigned NOT NULL
, `contact_id` int(6) unsigned NULL
, `name` varchar(200) NOT NULL
, PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `employee` (`id`, `contact_id`, `name`) VALUES
('1', '1', 'Mike'),
('2', null, 'John');
CREATE TABLE IF NOT EXISTS `contact`
( `id` int(6) unsigned NOT NULL
, `name` varchar(200) NOT NULL
, PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `contact`
(`id`, `name`) VALUES
('1', 'Alex');
CREATE TABLE IF NOT EXISTS `project`
( `id` int(6) unsigned NOT NULL
, `name` varchar(200) NOT NULL
, PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `project` (`id`, `name`) VALUES
('1','Test'),
('2', 'Mail');
CREATE TABLE IF NOT EXISTS `employee_projects`
( `id` int(6) unsigned NOT NULL
, `employee_id` int(6) unsigned NOT NULL
, `project_id` int(6) unsigned NOT NULL
, PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
INSERT INTO `employee_projects`
(`id`, `project_id`, `employee_id`) VALUES
('1', '1', '1'),
('2', '2', '1');
I think the below query will to the trick:
select e.,ep.,c.,p.
from emp e
left outer join emp_projects ep on e.emp_id = ep.emp_id
left outer join contact c on c.emp_id = e.emp_id
left outer join project p on p.proj_id = ep.proj_id
where e.emp_id=1

Get rows with largest Ids from the join of two table without sub queries

I'm having trouble implementing a JOIN query on these two tables.
Product Table contains products.
ProductInstance table contains version of product with pricing that were changed over time.
There should exactly be one row for each storeId even if it's null but should contain highest productInstanceId.
My Query can get rows with largest Ids for each product, but ignores StoreIds.
Select P.id as productId, PI.id as productInstanceId, P.name, PI.storeId, PI.price from products as P
LEFT JOIN productInstances AS PI
ON PI.productId = P.id
LEFT JOIN productInstances AS PI2
ON (PI2.productId = P.id and (PI.id < PI2.id ) )
WHERE PI2.id IS NULL
AND PI.id IS NOT NULL
Create Tables:
CREATE SCHEMA IF NOT EXISTS `TestDB` DEFAULT CHARACTER SET utf8 ;
USE `TestDB` ;
-- -----------------------------------------------------
-- Table `TestDB`.`products`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `TestDB`.`products` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(45) NOT NULL,
`description` VARCHAR(45) NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `TestDB`.`productInstances`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `TestDB`.`productInstances` (
`id` INT NOT NULL AUTO_INCREMENT,
`storeId` INT NULL,
`productId` INT NOT NULL,
`price` INT NOT NULL,
PRIMARY KEY (`id`, `productId`),
INDEX `fk_productInstances_products_idx` (`productId` ASC),
CONSTRAINT `fk_productInstances_products`
FOREIGN KEY (`productId`)
REFERENCES `TestDB`.`products` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
INSERT TEST DATA USING THIS QUERY
INSERT INTO `TestDB`.`products` (`name`) VALUES ('Product 1');
INSERT INTO `TestDB`.`products` (`name`) VALUES ('Product 2');
INSERT INTO `TestDB`.`productInstances` (`storeId`, `productId`, `price`) VALUES ('1', '1', '111');
INSERT INTO `TestDB`.`productInstances` (`productId`, `price`) VALUES ('1', '122');
INSERT INTO `TestDB`.`productInstances` (`productId`, `price`) VALUES ('1', '133');
INSERT INTO `TestDB`.`productInstances` (`storeId`, `productId`, `price`) VALUES ('1', '1', '115');
INSERT INTO `TestDB`.`productInstances` (`storeId`, `productId`, `price`) VALUES ('2', '1', '155');
For MySql 8.0+ you can use ROW_NUMBER() window function to get the max id for each productid and storeid:
select p.id productId,
pi.id productInstanceId,
p.name,
pi.storeId,
pi.price
from products p
left join (
select *, row_number() over (partition by storeId, productId order by id desc) rn
from productInstances
) pi on pi.productId = p.id and pi.rn = 1
For previous versions you can do the same with a correlated subquery:
select p.id as productId,
pi.id as productInstanceId,
p.name,
pi.storeId,
pi.price
from products p
left join (
select pi.* from productInstances pi
where pi.id = (
select max(id)
from productInstances
where productId = pi.productId and storeId <=> pi.storeId
)
) pi on pi.productId = p.id
See the demo.
Results:
> productId | productInstanceId | name | storeId | price
> --------: | ----------------: | :-------- | ------: | ----:
> 1 | 3 | Product 1 | null | 133
> 1 | 4 | Product 1 | 1 | 115
> 1 | 5 | Product 1 | 2 | 155
> 2 | null | Product 2 | null | null

SQL query remove only some of the duplicated rows in the results of a join

CREATE TABLE `rule` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`duplicate_mode` char(255) NOT NULL,
PRIMARY KEY (`id`)
)
INSERT INTO `rule` (`id`, `duplicate_mode`) VALUES
(1, 'single'),
(2, 'multiple');
CREATE TABLE `rule_tag` (
`rule_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
KEY `rule_id` (`rule_id`),
KEY `tag_id` (`tag_id`),
CONSTRAINT `rule_tag_ibfk_1` FOREIGN KEY (`rule_id`) REFERENCES `rule` (`id`),
CONSTRAINT `rule_tag_ibfk_2` FOREIGN KEY (`tag_id`) REFERENCES `tag` (`id`)
)
INSERT INTO `rule_tag` (`rule_id`, `tag_id`) VALUES
(1, 1),
(1, 2),
(2, 3),
(2, 4);
CREATE TABLE `tag` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` char(255) NOT NULL,
PRIMARY KEY (`id`)
)
INSERT INTO `tag` (`id`, `name`) VALUES
(1, 'foo'),
(2, 'bar'),
(3, 'bar'),
(4, 'baz');
Table visualization:
rule:
| id | duplicate_mode
| 1 | single
| 2 | multiple
rule_tag:
| rule_id | tag_id
| 1 | 1
| 1 | 2
| 2 | 3
| 2 | 4
tag:
| id | name
| 1 | Foo
| 2 | Bar
| 3 | Baz
| 4 | Bar
Wanted results (Note, the tag name that matches doesn't matter)
| rule_id | duplicate_mode | name
| 1 | single | foo
| 2 | multiple | bar
| 2 | multiple | baz
The duplicate mode column is supposed to define whether the rule is duplicated in the results
A SELECT DISTINCT with left joins would remove all duplicates, so is not a valid option.
If this is possible with a subquery, I have no idea how.
An UNION doing two separate queries, one for the single mode with a DISTINCT and another for the multiple mode without would solve it, but is there a way to do it in a single query?
I think it's also possible to do 2 joins with subqueries, but that's probably worse than UNION
If I understand correctly, you can use aggregation:
select r.id, r.duplicate_mode, max(t.name) as name
from rule r join
rule_tag rt
on rt.rule_id = r.id join
tag t
on rt.tag_id = t.id
group by r.id, r.duplicate_mode, (case when r.duplicate_mode = 'multiple' then t.id end);
Or filtering:
select r.id, r.duplicate_mode, max(t.name) as name
from rule r join
rule_tag rt
on rt.rule_id = r.id join
tag t
on rt.tag_id = t.id
where r.duplicate_mode = 'multiple' or
rt.tag_id = (select min(rt2.tag_id)
from rule_tag rt2
where rt.rule_id = rt.rule_id
);
Could be using union all between distinct and not distinct query for single and multiple
Select distinct rt.rule_id, r.duplicate_mode, t.name
from rule_tag rt
inner join rule r on r.id = rt.rule_id and duplicate_mode = 'single'
inner join tag t on t.id= rt.tag_id
UNION ALL
select rt.rule_id, r.duplicate_mode, t.name
from rule_tag rt
inner join rule r on r.id = rt.rule_id and duplicate_mode = 'multiple'
inner join tag t on t.id= rt.tag_id

mysql group_concat on multiple tables

This is the first time I ever use stackoverflow,.. be gentle on me ;)
I have little problem here with getting duplicated results from GROUP_CONCAT when using more than one JOIN on the map tables.
It is not easy to explain this, but I will try:
I have created a SQLFiddle for testing: http://sqlfiddle.com/#!9/d2b347/3
I want the query to be just one instead of 1 for all of the posts and then hammering on every test. But since the GROUP_CONCAT is merging those test results I am getting twice as much data than I want.
It is possible somehow to make the query more reliable. To always have the GROUP_CONCAT to be the exact numbers of tests?
I expect/want the output to be:
|---------|-----------------|------------|---------|-------------|
| post_id | flows | flow_types | powers | power_types |
|---------|-----------------|------------|---------|-------------|
| 1 | 100,140 | a,b | 1,1 | a,b |
|---------|-----------------|------------|---------|-------------|
| 2 | 200,200,200 | a,b,c | (null) | (null) |
|---------|-----------------|------------|---------|-------------|
but it is:
|---------|-----------------|------------|---------|-------------|
| post_id | flows | flow_types | powers | power_types |
|---------|-----------------|------------|---------|-------------|
| 1 | 100,100,140,140 | a,a,b,b | 1,1,1,1 | a,b,a,b |
|---------|-----------------|------------|---------|-------------|
| 2 | 200,200,200 | a,b,c | (null) | (null) |
|---------|-----------------|------------|---------|-------------|
and with GROUP_CONCAT DISTINCT I get:
|---------|-----------------|------------|---------|-------------|
| post_id | flows | flow_types | powers | power_types |
|---------|-----------------|------------|---------|-------------|
| 1 | 100,140 | a,b | 1 | a,b |
|---------|-----------------|------------|---------|-------------|
| 2 | 200 | a,b,c | (null) | (null) |
|---------|-----------------|------------|---------|-------------|
Here is the create query:
DROP TABLE IF EXISTS `posts`;
CREATE TABLE IF NOT EXISTS `posts` (
`post_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`post` varchar(256) CHARACTER SET ascii NOT NULL,
PRIMARY KEY (`post_id`),
UNIQUE KEY `UNQ_post` (`post`) USING HASH
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `posts_test1`;
CREATE TABLE IF NOT EXISTS `posts_test1` (
`post_id` bigint(20) unsigned NOT NULL,
`test1_id` bigint(20) unsigned NOT NULL,
`type_id` int(10) unsigned NOT NULL DEFAULT 1,
PRIMARY KEY (`post_id`,`test1_id`,`type_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `test1`;
CREATE TABLE IF NOT EXISTS `test1` (
`test1_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`flow` int(10) unsigned NOT NULL,
PRIMARY KEY (`test1_id`),
KEY `IDX_FLOW` (`flow`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `posts_test2`;
CREATE TABLE IF NOT EXISTS `posts_test2` (
`post_id` bigint(20) unsigned NOT NULL,
`test2_id` bigint(20) unsigned NOT NULL,
`type_id` int(10) unsigned NOT NULL DEFAULT 1,
PRIMARY KEY (`post_id`,`test2_id`,`type_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `test2`;
CREATE TABLE IF NOT EXISTS `test2` (
`test2_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`power` int(10) unsigned NOT NULL,
PRIMARY KEY (`test2_id`),
KEY `IDX_POWER` (`power`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `types`;
CREATE TABLE IF NOT EXISTS `types` (
`type_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`type` varchar(50) CHARACTER SET ascii DEFAULT NULL,
PRIMARY KEY (`type_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
INSERT INTO `types` (`type_id`, `type`) VALUES
(1, 'a'),
(2, 'b'),
(3, 'c');
INSERT INTO `posts` (`post_id`, `post`) VALUES
(1, 'test1'),
(2, 'test2');
INSERT INTO `test1` (`test1_id`, `flow`) VALUES
(1, 100),
(2, 140),
(3, 200),
(4, 200),
(5, 200);
INSERT INTO `posts_test1` (`post_id`, `test1_id`, `type_id`) VALUES
(1, 1, 1),
(1, 2, 2),
(2, 3, 1),
(2, 4, 2),
(2, 5, 3);
INSERT INTO `test2` (`test2_id`, `power`) VALUES
(1, 1),
(2, 1);
INSERT INTO `posts_test2` (`post_id`, `test2_id`, `type_id`) VALUES
(1, 1, 1),
(1, 2, 2);
And here are my select queries..
SELECT
p.post_id, p.post,
GROUP_CONCAT(t1.flow) flow,
GROUP_CONCAT(t1t.type) flow_types
FROM posts p
LEFT JOIN posts_test1 pt1 USING (post_id)
LEFT JOIN test1 t1 USING (test1_id)
LEFT JOIN types t1t ON (t1t.type_id = pt1.type_id)
GROUP BY p.post_id; # works fine
SELECT
p.post_id, p.post,
GROUP_CONCAT(t2.power) powers,
GROUP_CONCAT(t2t.type) power_types
FROM posts p
LEFT JOIN posts_test2 pt2 USING (post_id)
LEFT JOIN test2 t2 USING (test2_id)
LEFT JOIN types t2t ON (t2t.type_id = pt2.type_id)
GROUP BY p.post_id; # works fine
SELECT
p.post_id, p.post,
GROUP_CONCAT(t1.flow) flow,
GROUP_CONCAT(t1t.type) flow_types,
GROUP_CONCAT(t2.power) powers,
GROUP_CONCAT(t2t.type) power_types
FROM posts p
LEFT JOIN posts_test1 pt1 USING (post_id)
LEFT JOIN test1 t1 USING (test1_id)
LEFT JOIN types t1t ON (t1t.type_id = pt1.type_id)
LEFT JOIN posts_test2 pt2 USING (post_id)
LEFT JOIN test2 t2 USING (test2_id)
LEFT JOIN types t2t ON (t2t.type_id = pt2.type_id)
GROUP BY p.post_id; # getting duplicated GROUP_CONCAT results
SELECT
p.post_id, p.post,
GROUP_CONCAT(DISTINCT t1.flow) flow,
GROUP_CONCAT(DISTINCT t1t.type) flow_types,
GROUP_CONCAT(DISTINCT t2.power) powers,
GROUP_CONCAT(DISTINCT t2t.type) power_types
FROM posts p
LEFT JOIN posts_test1 pt1 USING (post_id)
LEFT JOIN test1 t1 USING (test1_id)
LEFT JOIN types t1t ON (t1t.type_id = pt1.type_id)
LEFT JOIN posts_test2 pt2 USING (post_id)
LEFT JOIN test2 t2 USING (test2_id)
LEFT JOIN types t2t ON (t2t.type_id = pt2.type_id)
GROUP BY p.post_id; # DISTINCT wipes the GROUP_CONCAT if same result...
Thanks and have a nice day!!
edit: added expected result as suggest, thanks :)
The issue here is that there are two different junction tables (and two different connection chains), originating from a single table post. So a linear JOIN chain does not work. Duplicates in one of the junction table leads to duplication in other chain, when linear joining is done.
One way is to consider these two different JOIN chains in two separate Derived Tables (subqueries inside the FROM clause), and determine their respective grouped/aggregated expressions. We can then JOIN back these two chains using post_id.
Query
SELECT
dt1.post_id,
dt1.flows,
dt1.flow_types,
dt2.powers,
dt2.power_types
FROM
(
SELECT
p.post_id,
GROUP_CONCAT(t1.flow) AS flows,
GROUP_CONCAT(typ.type) AS flow_types
FROM posts p
LEFT JOIN posts_test1 pt1
ON pt1.post_id = p.post_id
LEFT JOIN test1 t1
ON t1.test1_id = pt1.test1_id
LEFT JOIN types typ
ON typ.type_id = pt1.type_id
GROUP BY p.post_id
) AS dt1
JOIN
(
SELECT
p.post_id,
GROUP_CONCAT(t2.power) AS powers,
GROUP_CONCAT(typ.type) AS power_types
FROM posts p
LEFT JOIN posts_test2 pt2
ON pt2.post_id = p.post_id
LEFT JOIN test2 t2
ON t2.test2_id = pt2.test2_id
LEFT JOIN types typ
ON typ.type_id = pt2.type_id
GROUP BY p.post_id
) AS dt2
ON dt1.post_id = dt2.post_id;
Result
| post_id | flows | flow_types | powers | power_types |
| ------- | ----------- | ---------- | ------ | ----------- |
| 1 | 100,140 | a,b | 1,1 | a,b |
| 2 | 200,200,200 | a,b,c | | |
View on DB Fiddle

How to retrieve data from table with join

I'm using MySQL 5.5. with two tables in it:
DROP TABLE IF EXISTS `events_dictionary`;
CREATE TABLE `events_dictionary` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `events_dictionary` VALUES (1, 'Light'),(2, 'Switch'),(3, 'on'),(4, 'off');
DROP TABLE IF EXISTS `events_log`;
CREATE TABLE `events_log` (
`log_id` bigint(20) NOT NULL AUTO_INCREMENT,
`event_name_id` int(11) NOT NULL DEFAULT '0',
`event_param1` int(11) DEFAULT NULL,
`event_value1` int(11) DEFAULT NULL,
PRIMARY KEY (`log_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `events_log` VALUES (1, 1, 2, 3),(2, 1, 2, 4);
Table events_dictionary contains names for events_log events names,params and values.
So, my question is - how could i select data from event_log table with columns event_name_id, event_param1, event_value1 mapped to name values from events_dictionary table?
I tried to do this query:
SELECT name, event_param1, event_value1
FROM events_log
JOIN events_dictionary ON events_log.event_name_id = events_dictionary.id;
But, in this case i see only event_name_id replaced with values from events_dictionary, like this:
name | event_param1 | event_value1
Light | 1 | 1
Light | 1 | 2
And i want to replace event_param1, and event_value1 with names from events_dictionary too.
Thanks in advance!
You need to join to the events_dictionary multiple times
SELECT a.name, b.name, c.name
FROM events_log
JOIN events_dictionary a ON events_log.event_name_id = a.id
JOIN events_dictionary b ON events_log.event_param1 = b.id
JOIN events_dictionary c ON events_log.event_value1 = c.id;
PS
Your example for the event_log isn't that helpful , instead insert the values (1,1,2,3),(2,1,2,4) to turn the switch on and off for the light.
DS
You can use correlated subqueries:
SELECT name,
(SELECT t.name
FROM events_dictionary AS t
WHERE t.id = event_param1) AS param_name,
(SELECT t2.name
FROM events_dictionary AS t2
WHERE t2.id = event_value1) AS event_name
FROM events_log AS el
JOIN events_dictionary AS ed ON el.event_name_id = ed.id;
Demo here