MySQL: Concatenate different values as single value - mysql

In mysql db table I have projects with one to many relation with domain table like
projects
----------------
proId | domainId
----------------
1 1
1 2
2 1
3 3
domain
---------------------
domainId | domainName
---------------------
1 Web
2 Mobile
3 iPhone
I query
SELECT p.*, d.* FROM projects p LEFT JOIN domain d ON p.domainId = d.domainId
which results
result
-----------------------------
proId | domainId | domainName
-----------------------------
1 1 Web
1 2 Mobile
2 1 Web
3 3 iPhone
but is it possible to show all domains as single value with concatenation some thing like
-----------------------------
proId | domainId | domainName
-----------------------------
1 1, 2 Web, Mobile
2 1 Web
3 3 iPhone

probably you are looking for GROUP_CONCAT function.
SELECT a.proID,
GROUP_CONCAT(b.domainID) domainId,
GROUP_CONCAT(b.domainName) domainName
FROM projects a
LEFT JOIN domain b
ON a.domainID = b.domainID
GROUP BY a.proID
SQLFiddle Demo

For quick question I just posted major points now as by help of friends it is solved & now i am posting complete DB Schema & Query.
Schema
CREATE TABLE projects
(`projectId` int, `projectName` varchar(20))
;
INSERT INTO projects
(`projectId`, `projectName`)
VALUES
(1, 'P1'),
(2, 'P2'),
(3, 'P3')
;
CREATE TABLE domain
(`domainId` int, `domainName` varchar(6))
;
INSERT INTO domain
(`domainId`, `domainName`)
VALUES
(1, 'Web'),
(2, 'Mobile'),
(3, 'iPhone')
;
CREATE TABLE prodomain
(`domainId` int, `projectId` int)
;
INSERT INTO prodomain
(`domainId`, `projectId`)
VALUES
(1, 1),
(1, 1),
(3, 2),
(2, 3)
;
Query
SELECT p.projectId as proId, projectName, d.*,
GROUP_CONCAT(d.domainId separator ', ') as all_domains_id,
GROUP_CONCAT(d.domainName separator ', ') as all_domains_name
FROM projects p
LEFT JOIN projectdomains pd ON p.projectId = pd.projectId
LEFT JOIN domains d ON d.domainId = pd.domainId
GROUP BY p.projectId

SELECT
p.proId,
group_concat(d.domainId) as domainId,
group_concat(d.domainName) as domainName
FROM
projects p
inner JOIN
domain d ON p.domainId = d.domainId
group by p.proId
order by p.proId

Related

Return all possible combinations of values within a single column in MySQL

I'm using MySQL. How do I return all possible combination from a single column and count total corresponding column. For example:
name | grade
-------------------
john | A
any | B
cindy | C
kim | C
Will return something like this:
mark | count
-------------------
A | 1
B | 1
C | 2
AB | 2
AC | 3
BC | 3
ABC | 4
I've looking for a solution, the closest one is this Return all possible combinations of values within a single column in SQL. But in only generate combination and in ORACLE.
Here is the data set that I created for this question:
CREATE TABLE users
(`name` varchar(5), `grade` varchar(1))
;
INSERT INTO users
(`name`, `grade`)
VALUES
('john', 'A'),
('any', 'B'),
('cindy', 'C'),
('kim', 'C')
;
...and SQL fiddle of same:
http://sqlfiddle.com/#!9/36924d/1
You can use recursive common table expression:
with recursive cte (n) AS
(
select distinct cast(u.grade as char(255)) from users u
union all
select concat(u.grade, c.n)
from users u
join cte c on u.grade != c.n
where position(u.grade in c.n)=0
and u.grade < c.n
)
select c.n, count(*)
from cte c
join users u on position(u.grade in c.n)
group by c.n
See DBFiddle

Join 3 tables with Count

I am trying to write a simple query that will display all projects and their total number of team members, sorted alphabetically by project. If a project does not have assigned team members, that project should still be included in the output.
CREATE TABLE Project ( ID INT IDENTITY(1,1), ProjectName VARCHAR(50), DueDate
DATE)
CREATE TABLE Employee ( ID INT IDENTITY(1,1), EmployeeName VARCHAR(50) )
CREATE TABLE ProjectAssignment ( ID INT IDENTITY(1,1), ProjectID INT,
EmployeeID INT)
INSERT INTO Project VALUES ('Alpha', '1/1/2040'), ('Bravo', '3/1/2030'),
('Charlie', '2/1/2017'), ('Delta', '4/1/2017')
INSERT INTO Employee VALUES ('John'), ('Beth'), ('Tom'), ('Kim'), ('Jack')
INSERT INTO ProjectAssignment VALUES (1, 1), (1, 2), (2, 2), (2, 3), (3,
3), (3, 4), (1, 3)
--TABLE Project:
ID ProjectName DueDate
1 Alpha 2040-01-01
2 Bravo 2030-03-01
3 Charlie 2017-02-01
4 Delta 2017-04-01
--TABLE Employee:
ID EmployeeName
1 John
2 Beth
3 Tom
4 Kim
5 Jack
--TABLE ProjectAssignment:
ID ProjectID EmployeeID
1 1 1
2 1 2
3 2 2
4 2 3
5 3 3
6 3 4
7 1 3
Here is my wrong query:
SELECT n.ProjectName, Count(t.ProjectID) as NumMembers
FROM Project p
LEFT JOIN ProjectAssignment t ON p.EmployeeID = t.EmployeeID
LEFT JOIN employee e ON e.ProjectID = t.ProjectID
GROUP BY n.Project
ORDER BY n.Project
Desired Result:
| ProjectName | NumMembers |
+-------------+-------------+
| Alpha | 3 |
| Bravo | 2 |
| Charlie | 2 |
| Delta | null |
Please try this Mysql query. This will resolve your issue. We dont' require employee table join. If you are not taking any data from employee table then don't add employee table in join.
SELECT
p.name AS ProjectName,
Count( t.employeeID ) AS NumMembers
FROM
Project p
LEFT JOIN ProjectAssignment t ON p.id = t.projectID
GROUP BY
p.name
Output:
Project name NumMembers
Alpha 3
Bravo 2
Charlie 2
Delta 0
Few things
LEFT JOIN ProjectAssignment t ON p.EmployeeID = t.EmployeeID
is wrong as you can see p.EmployeeID do not exists on table Project
your join to employee is not needed at all
also finally i do not know how your fields names are. you post Name in sample data and projectName is used in your query and ddl (changed to your DDL instead of your query)
SELECT p.ProjectName, Count(DISTINCT pa.EmployeeID) as NumMembers
FROM Project p
LEFT JOIN ProjectAssignment pa ON p.ID = pa.ProjectID
GROUP BY p.ID, p.ProjectName
ORDER BY p.ProjectName
http://sqlfiddle.com/#!18/36df5/1
SELECT n.ProjectName, Count(t.ProjectID) as NumMembers FROM Project n LEFT JOIN ProjectAssignment t ON n.id = t.ProjectID GROUP BY t.ProjectID ORDER BY n.ProjectName
run this query
Just use this ( it seems join conditions are mixed ):
SELECT p.ProjectName, Count(t.ProjectID) as NumMembers
FROM Project p
LEFT JOIN ProjectAssignment t ON p.ID = t.ProjectID
LEFT JOIN employee e ON t.EmployeeID = e.ID
GROUP BY p.ProjectName
ORDER BY p.ProjectName;
ProjectName NumMembers
Alpha 3
Bravo 2
Charlie 2
Delta 0
SQL Fiddle Demo

how to do subquery with 3 tables and using where clause in multi values?

I want to do subquery with 3 tables and using where in multi values but I always get syntax error. I have to do reporting in Report Builder 3.0
Table A: record_id, Surname, Given Name
Table C: row_id, competency_code, competency_name
Table PC: link_id, record_id, row_id, attainment_date
I would like to join the tables into 1 table. One person will have some completion of competency_code and different with other person. the completion of competency_code based on the attainment_date. I also think to use iff function for attainment_date in competency_code value as complete/yes.
The table that I would like to create is:
Record_Id | Surname | GivenName | Code 1 | Code 2 | Code 3 | Code 4 | Code 5
01 | AA | AA | Complete | Complete | Complete | | Complete
02 | BB | BB | Complete | Complete | | Complete |
03 | CC | CC | | Complete | Complete | | Complete
here is the query that I tried to do.
select distinct a.id, a.surname, a.given_name
from all a
join
(
select pc.attainment_date
from personnel_competency pc
join
(
select c.code, c.name
from competency c)
competency c on (c.row_no = pc.linkid)
)
personnel_competency pc on (pc.id = a.id)
where c.code in ('ABC', 'BCD', 'ABE', 'DEA', 'DEF', 'POS', 'SAQ', 'LOP')
and pc.attainment_date < now()
order by a.record_id
My skill in SQL is very basic. Whether other ways to make the table like that?
Are you looking for a SQL to get your result. If so I think this is what you are looking for ..
It would help if you posted some sample data.
You can test it at
SQLFiddle
Here is the script ..
-- Generate schema and data
create table tableA (id int, surname varchar(30), given_name varchar(30));
create table tablePC (link_id int, id int, attainment_date datetime);
create table tableC (row_id int, competency_code varchar(20), Competency_name varchar(30));
insert into tableA (id, surname, given_name)
values (1, 'AA', 'AAgn')
, (2, 'BB', 'BBgn')
insert into tablePC (link_id, id, attainment_date)
values (1, 1, '2014-09-11')
, (2, 1, '2014-09-10')
, (3, 2, '2014-09-11')
insert into tableC (row_id, competency_code, Competency_name)
values (1, 'ABC', 'completed\Yes')
, (1, 'BCD', 'completed')
, (1, 'ABE', 'completed')
, (2, 'ABC', 'completed')
, (2, 'BCD', 'completed')
, (3, 'ABC', 'completed')
, (3, 'ABE', 'completed')
-- ===============
select *
from tableA TA
inner join tablePC PC
on TA.id = PC.id
inner join
(
select row_id, [ABC] as ABC, [BCD] as BCD, [ABE] as ABE
from tableC TC
pivot
(
max(Competency_name)
for Competency_code in ([ABC], [BCD], [ABE])
) as TCPVT
) TC
on PC.link_id = TC.row_id
where PC.attainment_date < GETDATE()

Columns with multiple values

I have one table called Employee that contains the following information like
ID Name Skills
1 xyz java,php,dotnet
2 abc ruby,java,python
Skills column saves comma seprated values. it could be one or more.
I want to design a query based on OR operate.When user search java, Database displays two employees likes xyz, abc.
I have tried this query but no result comes out:
SELECT m
FROM Employee m
Where m.Skills LIKE '%JAVA% MS PAINT%'
Any Suggestion?
Ideally you should not store the data in a comma-separated list. You should create a join table between the employees and the skills:
CREATE TABLE employees (`e_id` int, `e_name` varchar(3));
INSERT INTO employees (`e_id`, `e_name`)
VALUES
(1, 'xyz'),
(2, 'abc');
CREATE TABLE skills (`s_id` int, `s_name` varchar(6));
INSERT INTO skills (`s_id`, `s_name`)
VALUES
(1, 'java'),
(2, 'php'),
(3, 'dotnet'),
(4, 'ruby'),
(5, 'python');
CREATE TABLE employees_skills (`e_d` int, `s_id` int);
INSERT INTO employees_skills
(`e_d`, `s_id`)
VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 4),
(2, 1),
(2, 5);
Then when you want to select from the tables you will use:
select *
from employees e
inner join employees_skills es
on e.e_id = es.e_id
inner join skills s
on es.s_is = s.s_id
where s.s_name in ('java', 'ruby')
Or you can use the OR clause:
select *
from employees e
inner join employees_skills es
on e.e_id = es.e_id
inner join skills s
on es.s_is = s.s_id
where s.s_name = 'java'
or s.s_name = 'ruby'
use like not good solution. Full scan and slow query.
Create new table with catalog of skills.
Create table user_skills
You should set up your tables like this:
Employee:
ID | Name
---+------
1 | xyz
2 | abc
Skill:
ID | Name
---+------
1 | java
2 | php
3 | dotnet
4 | ruby
5 | python
EmployeeSkills:
ID | EmployeeID | SkillID
---+------------+----------
1 | 1 | 1
2 | 1 | 2
3 | 1 | 3
4 | 2 | 4
5 | 2 | 1
6 | 2 | 5
the query to find employees with skills in java would look like this
SELECT
E.Name
FROM
Employee AS E
INNER JOIN
EmployeeSkill AS ES
ON
ES.EmployeeID = E.ID
INNER JOIN
Skill AS S
ON
ES.SkillID = S.ID
WHERE
S.Name = 'java'
select name from table where skill like '%java%' should do

MySQL self join question

Take a look at the following mySQL query:
SELECT fname,lname FROM users WHERE users.id IN (SELECT sub FROM friends WHERE friends.dom = 1 )
The above query first creates a set of ALL the friends.sub's via the inner query, and then the outer query selects a list of users where user ids are contained within the set created by the inner query (ie the union of the two sets).
And this works fine. But if you needed the inner set to contain not only the subs where dom = 1, but also the doms where sub = 1, like so:
Outer query remains same as above, pure pseudocode:
(SELECT sub FROM friends WHERE friends.dom = 1 )
***AND***
(SELECT dom FROM friends WHERE friends.sub = 1 )
Is it possible to make this sort of functionality with the inner query??
Any help or assistance appreciated guys;-D
Thanks a lot guys, my headache is gone now!
Try this:
SELECT u.fname, u.lname
FROM users u
INNER JOIN friends f
ON (u.id = f.sub AND f.dom = 1)
OR (u.id = f.dom AND f.sub = 1)
I'm not sure if I correctly understand what sub and dom represent, but it looks like you can use a UNION in there:
SELECT fname, lname
FROM users
WHERE users.id IN
(
SELECT sub FROM friends WHERE friends.dom = 1
UNION
SELECT dom FROM friends WHERE friends.sub = 1
);
Test case:
CREATE TABLE users (id int, fname varchar(10), lname varchar(10));
CREATE TABLE friends (dom int, sub int);
INSERT INTO users VALUES (1, 'Bob', 'Smith');
INSERT INTO users VALUES (2, 'Peter', 'Brown');
INSERT INTO users VALUES (3, 'Jack', 'Green');
INSERT INTO users VALUES (4, 'Kevin', 'Jackson');
INSERT INTO users VALUES (5, 'Steven', 'Black');
INSERT INTO friends VALUES (1, 2);
INSERT INTO friends VALUES (1, 3);
INSERT INTO friends VALUES (4, 1);
INSERT INTO friends VALUES (3, 4);
INSERT INTO friends VALUES (5, 2);
Result:
+-------+---------+
| fname | lname |
+-------+---------+
| Peter | Brown |
| Jack | Green |
| Kevin | Jackson |
+-------+---------+
3 rows in set (0.00 sec)
That said, #Alec's solution is probably more efficient.