Columns with multiple values - mysql

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

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

MySQL - Join if no duplicate

I want to Join to table. the condition is I want to only join those rows which have only one row to match. eg.
books:
id | name | price
1 | book1 | 19
2 | book2 | 19
3 | book3 | 30
price_offer:
id | offer | price
1 | offer1 | 19
2 | offer2 | 30
so now if I do select query on these table:
SELECT * FROM price_offer
JOIN books ON price_offer.price = books.price
I only want to join book with id 3 as it have only one match with price_offer table.
You could use a self join for books table to pick a book with only single match
select po.*, b1.*
from price_offer po
join books b1 on po.price = b1.price
join (
select price,max(id) id
from books
group by price
having count(*) = 1
) b2 on b1.id = b2.id
Demo
Try following query:
Sample data:
create table books(id int, name varchar(10), price int);
insert into books values
(1, 'book1', 19),
(2, 'book2', 19),
(3, 'book3', 30);
create table price_offer(id int, offer varchar(10), price int);
insert into price_offer values
(1, 'offer1', 19),
(2, 'offer2', 30);
Query:
select max(b.id)
from price_offer p
left join books b on b.price = p.price
where p.id is not null
group by b.price
having count(*) = 1;
If you want to avoid nesting queries where you have to use self-joins, you can use window-functions of MySQL 8.0.11, which are exactly for cases like this

INNER JOIN not working for me

I'm currently working on a database for my Magic: The Gathering Playgroup which keeps track of decks and more specific which decks win against how many others and so on.
The table "Wins" looks like the following:
PNr (Playernumber which is primary key in the table players)
DNr (Decknumber which is primary key in the table decks)
Date (combined primary key with MNr)
MNr (Matchnumber of the day)
Pl (Amount of Players in the game)
Loc (Location)
Code (containing of all the playing players Shortcuts, e.g. AMT for the Players Alex, Martin and Tobias, see below)
The table Players is pretty easy:
PNr
Pname (Playersname)
SC (Players Shortcut)
Now I wanted to make a Query that provides a table of Expected Winrate (which is 1/4 in a 4 Player game, 1/5 in a 5 player game etc.) and the actual amount of Wins for each player (and later on Expected and actual Winrate but I think I can workthat out on my own once I got this baby to work).
So far I've come up with smth like this:
SELECT a.'Player',a.'ExpectedWinrate',b.'Wins'
FROM(
SELECT
ROUND(((SUM(1/Pl))/Count(*))*100, 1) as 'ExpectedWinrate',
Players.Pname as 'Player'
FROM
Wins, Players
WHERE Code LIKE CONCAT('%', Players.SC, '%')
GROUP BY Players.Pname) a
INNER JOIN
(SELECT
Count(*) as 'Wins',
Players.Pname as 'Players'
FROM Players, Wins
WHERE Players.PNr = Wins.PNr
GROUP BY Players.Pname
ORDER BY Count(*) desc) b ON 'Players' = 'Player';
The problem that I've run into is that I need the Count(*) for two different things in one query so I had to make two independent ones and join them, but I don't know how to "name" them (in this case I tried with "a" and "b") in order to use expressions like a.'Player', a.'ExpectedWinrate', etc.
Can anyone help a MYSQL newb?^^
greetzSP
EDIT: added expample tables...
CREATE TABLE Players
(
PNr int primary key,
Pname varchar(20),
SC varchar(1)
);
INSERT INTO Players
(PNr, Pname, SC)
VALUES
(1, 'Tobias', 'T'),
(2, 'Alex', 'A'),
(3, 'Martin', 'M'),
(4, 'Maria', 'R');
CREATE TABLE Wins
(
PNr int,
DNr int,
Pl int,
Code varchar(10)
);
INSERT INTO Wins
(PNr, DNr, Pl, Code)
VALUES
(1, 13, 3, 'ATM'),
(4, 1, 4, 'RTMA'),
(3, 20, 3, 'RTM');
Wins: (leaving out columns that don't matter in this query)
| PNR | DNR | PL | CODE |
|-----|-----|----|------|
| 1 | 13 | 3 | ATM |
| 4 | 1 | 4 | RTMA |
| 3 | 20 | 3 | RTM |
Players:
| PNR | PNAME | SC |
|-----|--------|----|
| 1 | Tobias | T |
| 2 | Alex | A |
| 3 | Martin | M |
| 4 | Maria | R |
SELECT a.Player ,a.ExpectedWinrate ,b.Wins
FROM(
SELECT
ROUND(((SUM(1/w.Pl))/Count(*))*100, 1) as 'ExpectedWinrate'
,p.Pname as 'Player'
FROM Wins w inner join Players p
on w.Code LIKE CONCAT('%', p.SC, '%')
GROUP BY p.Pname
) a
inner join
(
SELECT
Count(*) as 'Wins'
,p.Pname as 'Players'
FROM Players p inner join Wins w
on p.PNr = w.PNr
GROUP BY p.Pname
--ORDER BY Count(*) desc
) b
ON a.Player = b.Players
I have tested it on SQL Server, try on MySQL

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()

MySQL: Concatenate different values as single value

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