Join 3 Tables in a MySql Query - mysql

i have this 3 tables in a MySql Database.
users
+----+------+--------+------+
| Id | Name | Status | Role |
+----+------+--------+------+
| 1 | A | Aktiv | Op |
| 2 | B | Aktiv | Op |
| 3 | C | Aktiv | Op |
| 4 | D | Aktiv | Op |
+----+------+--------+------+
cnt
+----+------+------------+------+
| Id | Name | Date | Type |
+----+------+------------+------+
| 1 | A | 2017-11-09 | Web |
| 2 | B | 2017-11-09 | Web |
| 3 | C | 2017-11-09 | Web |
| 4 | C | 2017-11-09 | Inb |
| 5 | A | 2017-11-09 | Web |
+----+------+------------+------+
Lead
+----+------+------------------+------------+
| Id | Name | Date | Type |
+----+------+------------------+------------+
| 1 | A | 2017-11-09 00:24 | Imported |
| 2 | B | 2017-11-09 09:32 | Activation |
| 3 | B | 2017-11-09 10:56 | Activation |
| 4 | D | 2017-11-09 12:21 | Activation |
| 5 | D | 2017-11-10 12:22 | Activation |
+----+------+------------------+------------+
I'm trying to join them in a main table but with no success, the query i'm using is:
SELECT IFNULL(u.Name,'Total') as "Name",
Sum(IF(c.Type = 'Web',1,0)) as "Cnt Web",
Sum(IF(l.Type = 'Activation',1,0)) as "Lead Web"
FROM users u
LEFT JOIN cnt c ON u.Name = c.Name and c.Date = '2017-11-09'
LEFT JOIN lead l ON u.Name = l.Name and l.Date>= '2017-11-09' AND l.Date< '2017-11-10'
WHERE u.Status = 'Aktiv' AND u.Role = 'Op'
GROUP BY u.Name WITH ROLLUP
The result i need is a table like this:
+----+------+--------+---------+
| Id | Name | Cnt Web| Lead Web|
+----+------+------------------+
| 1 | A | 2 | 0 |
| 2 | B | 1 | 2 |
| 3 | C | 1 | 0 |
| 4 | D | 0 | 1 |
+----+------+------------------+
When i try to join the first table with the second or the first with the third, i get the correct result, but i can't get the needed result when i join them all.
Any answer is the most welcomed. Thank you in advance.

Here's a solution using correlated sub-queries
SELECT u.Id,
u.Name,
(SELECT COUNT(Name) FROM cnt WHERE Name = u.name AND type = 'Web' AND Date = '2017-11-09') AS cnt_web,
(SELECT COUNT(Name) FROM lead WHERE Name = u.name AND type = 'Activation' AND Date>= '2017-11-09' AND Date< '2017-11-10') AS cnt_lead
FROM users u
WHERE u.Status = 'Aktiv' AND u.Role = 'Op'

Related

Update a table based on joining 4 tables

I have the following tables:
agent
+-------------------------------------+
| id | name | desc | comment |
|-------------------------------------+
| 1 | agent1 | agent 1 | sss |
| 2 | agent2 | agent 2 | eee |
|-------------------------------------|
agent_old
+-------------------------------------+
| id | name | desc | comment |
|-------------------------------------+
| 1 | agent1 | agent 1 | sss |
| 2 | agent3 | agent 3 | eee |
|-------------------------------------|
auth
+-------------------------------+
| id | login | password |
|-------------------------------+
| 1 | agent1 | xxxxxxx |
| 2 | agent2 | yyyyyy |
|-------------------------------|
auth_old
+-------------------------------+
| id | login | password |
|-------------------------------+
| 1 | oldagent1 | wwwwww |
| 2 | oldagent2 | qqqqqq |
|-------------------------------|
I need the resultant tables like this:
agent
+-------------------------------------+
| id | name | desc | comment |
|-------------------------------------+
| 1 | agent1 | agent 1 | sss |
| 2 | agent2 | agent 2 | eee |
|-------------------------------------|
auth
+-------------------------------+
| id | login | password |
|-------------------------------+
| 1 |oldagent1 | wwwwww |
| 2 | agent2 | yyyyyy |
|-------------------------------|
This is what I have got but does not run:
update auth a
set
a.login = oa.login,
a.password = oa.password
from (
select o.login,
o.password
from auth_old o
join agent na
join agent_old ago
on ago.id = o.id
and na.name = ago.name
and na.desc = ago.desc
) oa
where a.id = na.id
In mysql you could use this sintax but you have not an id in you from ( select ) oa .. i have added the o.id for this (hope is the right one)
update auth a
inner join (
select o.login,
o.password ,
na.id
from auth_old o
join agent na
join agent_old ago
on ago.id = o.id
and na.name = ago.name
and na.desc = ago.desc
) oa on a.id = oa.id
set
a.login = oa.login,
a.password = oa.password
(and as suggested by Bill Karvin you have a wrong table alias na instead of oa)

SQL Query: 3 tables highest Value plus rest of row plus

i'm currently stuck on a sql-query, trying to find a solution, but making me headache for 2 stays now. i've got 3 tables
user-table:
+-----+----------+-----------+
| pid | username | role |
+-----+----------+-----------+
| 1 | user1 | patient |
| 2 | user2 | patient |
| 3 | user3 | doc |
| 4 | user4 | assistant |
| 5 | user5 | patient |
+-----+----------+-----------+
base-dat:
+-----+---------+-------+------------+
| pid | surname | name | birthdate |
+-----+---------+-------+------------+
| 1 | smith | john | 1950-07-31 |
| 2 | jackson | sarah | 1948-08-15 |
+-----+---------+-------+------------+
med-dat:
+-----+-----+---------------+--------+--------+
| mid | pid | dateLastEntry | weight | pulse |
+-----+-----+---------------+--------+--------+
| 1 | 1 | 2017-12-01 | 86 | 65 |
| 2 | 1 | 2017-12-02 | 84 | 70 |
| 3 | 1 | 2017-12-03 | 80 | 67 |
| 4 | 2 | 2017-11-15 | 66 | 60 |
| 5 | 2 | 2017-11-17 | 60 | 64 |
+-----+-----+---------------+--------+--------+
I'm trying to get the max(dateLastEntry) for each user with role patient, showing their pid, name, surname, weight, pulse in a single row - , even if there is no med-data entry for the patient: something like this:
+-----+---------+-------+------------+--------+-------+
| pid | surname | name | lastEntry | weight | pulse |
+-----+---------+-------+------------+--------+-------+
| 1 | smith | john | 2017-12-02 | 84 | 70 |
| 2 | jackson | sarah | 2017-11-17 | 60 | 64 |
| 5 | NONE | NONE | NONE | NONE | NONE |
+-----+---------+-------+------------+--------+-------+
Atm my statement looks like this, but can't get the proper result:
select b.pid, s.surname, s.name, max(m.date) as lastEntry, m.weight, m.pulse
from users b
left join med-dat m on b.pid = m.pid
left join base-dat s on m.pid = s.pid
where b.role = 'Patient'
group by b.pid, s.surname, s.name, m.weight;
You can rewrite your query as below to get the desired output
select b.pid, s.surname, s.name, m.dateLastEntry as lastEntry, m.weight, m.pulse
from users b
left join med_dat m on b.pid = m.pid
left join base_dat s on m.pid = s.pid
left join med_dat m1 on m.pid = m1.pid
and m.dateLastEntry < m1.dateLastEntry
where m1.pid is null
and b.role = 'Patient'
DEMO
Edit from comment, join base_dat using pid from user table
select b.pid, s.surname, s.name, m.dateLastEntry as lastEntry, m.weight, m.pulse
from users b
left join med_dat m on b.pid = m.pid
left join base_dat s on b.pid = s.pid
left join med_dat m1 on m.pid = m1.pid and m.dateLastEntry < m1.dateLastEntry
where m1.pid is null
and b.role = 'Patient'
group by b.pid, s.surname, s.name, m.weight;
Demo

Left join select using Propel ORM

I have 3 table
major table:
+----+------------+
| id | major |
+----+------------+
| 1 | Computer |
| 2 | Architect |
| 3 | Designer |
+----+------------+
classroom table:
+----+----------+-------+
| id | major_id | name |
+----+----------+-------+
| 1 | 1 | A |
| 2 | 1 | B |
| 3 | 1 | C |
| 4 | 2 | A |
| 5 | 2 | B |
| 6 | 3 | A |
+----+----------+-------+
and finally, student_classroom table
+----+------------+--------------+----------+
| id | student | classroom_id | status |
+----+------------+--------------+----------+
| 1 | John | 1 | Inactive |
| 2 | Defou | 2 | Active |
| 3 | John | 2 | Active |
| 4 | Alexa | 1 | Active |
| 5 | Nina | 1 | Active |
+----+------------+--------------+----------+
how can I use propel to build query below
select
a.id,
a.major,
b.number_of_student,
c.number_of_classroom
from major a
left join (
select
major.major_id,
count(student_classroom.id) as number_of_student
from major
left join classroom on classroom.major_id = major.id
left join student_classroom on student_classroom.classroom_id = classroom.id
where student_classroom.`status` = 'Active'
group by major_id
) b on b.major_id = a.major_id
left join (
select
major.major_id,
count(classroom.id) as number_of_classroom
from major
left join classroom on classroom.major_id = major.id
group by major_id
) c on c.major_id = a.major_id
Because I want the final result would be something like this, I spend hours trying to figure it out without success.
+----+------------+-------------------+---------------------+
| id | major | number_of_student | number_of_classroom |
+----+------------+-------------------+---------------------+
| 1 | Computer | 4 | 3 |
| 2 | Architect | 0 | 2 |
| 3 | Designer | 0 | 1 |
+----+------------+-------------------+---------------------+
Try this
select
m.id,
m.major,
count(distinct s.id) as number_of_student ,
count(distinct c.id) as number_of_classroom
from major m
left join classroom c on
(m.id = c.major_id)
left join student_classroom s
on (s.classroom_id = c.id and c.major_id = m.id and s.status = 'active')
group by m.id
order by m.id

Create view from multiple queries

I'm currently doing a sql script using the following tables in a database:
Menu table (contains the information about dishes):
+----------+--------------+--------+-------------+
| id_plato | nombre_plato | precio | tipo |
+----------+--------------+--------+-------------+
| 1 | peces | 100 | entrada |
| 2 | caca | 20 | rolls_fondo |
| 3 | plato1 | 200 | bajativo |
| 4 | plato2 | 200 | entrada |
| 5 | plato3 | 200 | entrada |
| 6 | plato4 | 200 | entrada |
| 7 | plato5 | 200 | entrada |
| 8 | plato6 | 200 | entrada |
| 9 | plato7 | 200 | entrada |
| 10 | plato8 | 200 | entrada |
| 11 | plato9 | 200 | entrada |
| 12 | plato10 | 200 | entrada |
| 13 | plato11 | 200 | entrada |
| 14 | plato1 | 200 | entrada |
+----------+--------------+--------+-------------+
Boleta table (contains the informatio of all sales):
+-----------+------+--------------+
| id_boleta | sexo | precio_final |
+-----------+------+--------------+
| 1 | m | 1 |
| 2 | f | 1 |
| 3 | f | 1 |
| 4 | m | 1 |
+-----------+------+--------------+
BoletaDetalle table (contains the information of each dish bought on a given sale):
+------------+-----------+----------+----------------+
| id_detalle | id_boleta | id_plato | precio_detalle |
+------------+-----------+----------+----------------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 1 | 1 |
| 3 | 1 | 2 | 1990 |
| 4 | 2 | 1 | 5 |
| 5 | 3 | 4 | 1 |
| 6 | 4 | 2 | 1 |
| 7 | 5 | 4 | 1 |
| 8 | 4 | 2 | 1 |
+------------+-----------+----------+----------------+
Basically, this is a small program for a small restaurant and I have been asked to show a quick report trough an sql script that displays a view containing the favorite dish of a certain group of costumers. For example, based on costumer's gender as follows:
| Sex | Type |
+------------------+
| M | entrada |
| F | bajativo |
I'm having a lot of trouble trying to figure this out despite of it being an easy task.
This is what I have so far:
DROP VIEW IF EXISTS v1;
CREATE VIEW v1 (Tipo, CantidadMujer, CantidadHombre)
AS
SELECT m.tipo as Tipo, COUNT(bd.id_plato) as 'Cantidad Mujer', COUNT(bd2.id_plato) as 'Cantidad Hombre'
FROM Menu m
LEFT JOIN BoletaDetalle bd
INNER JOIN Boleta b
on (bd.id_boleta = b.id_boleta AND b.sexo = 'f')
on bd.id_plato = m.id_plato AND m.tipo = 'entrada'
LEFT JOIN BoletaDetalle bd2
INNER JOIN Boleta b2
on (bd2.id_boleta = b2.id_boleta AND b2.sexo = 'm')
on bd2.id_plato = m.id_plato AND m.tipo = 'entrada'
GROUP BY(m.tipo);
SELECT * FROM v1;
I was thinking of creating a view like the one above with the amount of dishes bought per each gender (on each dish type) and then create a second view (the final one) by getting the maximum value per category. I'm really lost here so any help would be appreciated.
Are you looking for something like this?
CREATE VIEW sexo_tipo_view AS
SELECT b.sexo, m.tipo, COUNT(d.id_plato) total
FROM boletadetalle d JOIN boleta b
ON d.id_boleta = b.id_boleta JOIN menu m
ON d.id_plato = m.id_plato
GROUP BY b.sexo, m.tipo
ORDER BY sexo, total DESC;
CREATE VIEW sexo_tipo_favorites_view AS
SELECT sexo, tipo
FROM sexo_tipo_view
GROUP BY sexo;
SELECT s.sexo, COALESCE(v.tipo, '-') tipo
FROM
(
SELECT 'f' sexo UNION ALL
SELECT 'm'
) s LEFT JOIN sexo_tipo_favorites_view v
ON s.sexo = v.sexo;
or without views
SELECT s.sexo, COALESCE(v.tipo, '-') tipo
FROM
(
SELECT 'f' sexo UNION ALL
SELECT 'm'
) s LEFT JOIN
(
SELECT sexo, tipo
FROM
(
SELECT b.sexo, m.tipo, COUNT(d.id_plato) total
FROM boletadetalle d JOIN boleta b
ON d.id_boleta = b.id_boleta JOIN menu m
ON d.id_plato = m.id_plato
GROUP BY b.sexo, m.tipo
ORDER BY sexo, total DESC
) a
GROUP BY sexo
) v
ON s.sexo = v.sexo;
Sample output (in both cases):
| SEXO | TIPO |
|------|-------------|
| f | entrada |
| m | rolls_fondo |
Here is SQLFiddle demo

Get all users even if no records in another table

I'm facing a problem here :
I have two tables :
A users table :
+----+---------------+----------+
| id | username | company |
+----±---------------±----------+
| 1 | John | 0 |
| 2 | Jack | 0 |
| 3 | Casimir | 0 |
±----±---------------±----------±
A orders table :
+----+---------------+----------+--------+
| id | date | iduser | status |
+----±---------------±----------+--------+
| 1 | 2012-05-28 | 1 | 1 |
| 2 | 2012-05-25 | 1 | 1 |
| 3 | 2012-04-28 | 2 | 1 |
| 4 | 2012-03-28 | 1 | 1 |
| 5 | 2012-02-28 | 2 | 0 |
±----±---------------±----------±--------+
What I'm trying to do is to get a result like this :
+----------+---------------+-------------+
| username | COUNT(order) | MAX(date) |
+----------±---------------±-------------+
| John | 3 | 2012-05-28 |
| Jack | 1 | 2012-04-28 |
| Casimir | 0 | NULL |
±----------±---------------±-------------±
Here's the request I have for the moment :
SELECT u.username, COUNT(o.id), MAX(o.date)
FROM users u
INNER JOIN orders ON u.id = o.iduser
WHERE o.status = 1
GROUP BY u.id
This request gives me a result like :
+----------+---------------+-------------+
| username | COUNT(order) | MAX(date) |
+----------±---------------±-------------+
| John | 3 | 2012-05-28 |
| Jack | 1 | 2012-04-28 |
±----------±---------------±-------------±
As you can see, the user Casimir is not shown as he made no order. How can I modify my request to get the result I need please ?
Thanks !
A LEFT JOIN or LEFT OUTER JOIN will include all rows of the inital table, including those where there is no match in the joined-to table
SELECT u.username, COUNT(o.id), MAX(o.date)
FROM users u
LEFT OUTER JOIN orders o ON u.id = o.iduser AND o.status = 1
GROUP BY u.id
You need to use an OUTER JOIN instead of your current INNER JOIN.
Have a look at Jeff's post here to see how they differ:
http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html