Mysql table joins using a where clause - mysql

I am trying to run a MySQL query against a database and join 3 tables together.
I have 3 tables in the database;
Table containing the important data
+----+-------+----------------------+
| id | name | value |
+----+-------+----------------------+
| 1 | data1 | First piece of data |
| 2 | data2 | Second piece of data |
| 3 | data3 | Third piece of data |
+----+-------+----------------------+
Table containing flag_id to flag_name
+----+-------+-------------+
| id | name | description |
+----+-------+-------------+
| 1 | flag1 | NULL |
| 2 | flag2 | NULL |
| 3 | flag3 | NULL |
| 4 | flag4 | NULL |
+----+-------+-------------+
Table containing the one-to-many data to flag mapping
+----+---------+--------+---------+
| id | type_id | status | data_id |
+----+---------+--------+---------+
| 1 | 1 | 0 | 1 |
| 2 | 2 | 0 | 1 |
| 3 | 4 | 1 | 1 |
| 4 | 2 | 0 | 2 |
| 5 | 3 | 0 | 2 |
| 6 | 4 | 1 | 2 |
| 7 | 3 | 0 | 3 |
| 8 | 4 | 1 | 3 |
+----+---------+--------+---------+
I want to be able to have a single query that will show me each named flag as a column for each piece of data. In searching the web, I found an example doing it using this query:
select d.id, d.name, d.value,
MAX(CASE WHEN f.type_id = 1 THEN f.status ELSE NULL END) as flag1,
MAX(CASE WHEN f.type_id = 2 THEN f.status ELSE NULL END) as flag2,
MAX(CASE WHEN f.type_id = 3 THEN f.status ELSE NULL END) as flag3,
MAX(CASE WHEN f.type_id = 4 THEN f.status ELSE NULL END) as flag4
from data d
inner join flags f on f.data_id = d.id
group by d.id
Which gives the result I want.
+----+-------+----------------------+-------+-------+-------+-------+
| id | name | value | flag1 | flag2 | flag3 | flag4 |
+----+-------+----------------------+-------+-------+-------+-------+
| 1 | data1 | First piece of data | 0 | 0 | NULL | 1 |
| 2 | data2 | Second piece of data | NULL | 0 | 0 | 1 |
| 3 | data3 | Third piece of data | NULL | NULL | 0 | 1 |
+----+-------+----------------------+-------+-------+-------+-------+
The problem is that I need to add a where clause to filter on specific flags, but I get the error that 'flag4' is an Unknown column, which is because an alias cannot be used in a where clause.
How do I accomplish this, preferably in a single query that I can use with a 'where' clause?

Instead of use where, use having.
The flag columns are the result of an aggregating operation, so, if you want to apply a selection criteria on them, you have to use having. Example:
select d.id, d.name, d.value,
MAX(CASE WHEN f.type_id = 1 THEN f.status ELSE NULL END) as flag1,
MAX(CASE WHEN f.type_id = 2 THEN f.status ELSE NULL END) as flag2,
MAX(CASE WHEN f.type_id = 3 THEN f.status ELSE NULL END) as flag3,
MAX(CASE WHEN f.type_id = 4 THEN f.status ELSE NULL END) as flag4
from data d
inner join flags f on f.data_id = d.id
group by d.id
havig flag1 = 0

Related

SQL query to return specific labels if exist (0 if it does not exist)

There are two tables given, tag and media.
mysql> select * from media;
+----+---------+----------+
| id | name | duration |
+----+---------+----------+
| 1 | cat.mp4 | 3.4 |
| 2 | dog.mp4 | 8 |
+----+---------+----------+
mysql> select * from tag;
+----+----------+-------+--------+------------+
| id | media_id | type | value | confidence |
+----+----------+-------+--------+------------+
| 1 | 1 | LABEL | cat | 0.9 |
| 2 | 1 | LABEL | person | 0.6 |
| 3 | 1 | TEXT | kitty | 0.95 |
| 4 | 2 | LABEL | dog | 0.8 |
| 5 | 2 | LABEL | person | 0.75 |
| 6 | 2 | TEXT | food | 0.7 |
+----+----------+-------+--------+------------+
I need to get the output table by joining two tables that gives media_id, name, duration and label of the value from tag such that if the value is cat, the confidence of cat will be inserted into label_cat column otherwise 0 will be inserted.
Something like this:
+----------+---------+----------+-----------+-----------+--------------+
| media_id | name | duration | label_cat | label_dog | label_person |
+----------+---------+----------+-----------+-----------+--------------+
| 1 | cat.mp4 | 3.4 | 0.9 | 0 | 0.6 |
| 2 | dog.mp4 | 8 | 0 | 0.8 | 0.75 |
+----------+---------+----------+-----------+-----------+--------------+
If I understand correctly, you want conditional aggregation:
select m.id, m.name, m.duration,
max(case when t.value = 'cat' then t.confidence end) as label_cat,
max(case when t.value = 'dog' then t.confidence end) as label_dog,
max(case when t.value = 'person' then t.confidence end) as label_person
from media m left join
tag t
on m.id = t.media_it
group by m.id, m.name, m.duration
Select t.media_id,m.name,m.duration,
case "label_cat " when t.value ='cat' then
t.confidence else 0 end case,
case "label_dog" when t.value ='dog' then
t.confidence else 0 end case,
case "label_person" when t.value ='person' then
t.confidence else 0 end case
from
tag t right join media m on t.id=m.id
group by t.media_id

Mysql, Dynamic query for rows to column

I've three tables with name employee, employee_products, product_type
reference : http://sqlfiddle.com/#!9/00436/4
I'm trying to get data as
Let this table is Table_1
using this query:
select emp.name,
(select count(*) from employee_products where product_type_id = 1 and employee_id = emp.id) as Service,
(select count(*) from employee_products where product_type_id = 2 and employee_id = emp.id) as Product,
(select count(*) from employee_products where product_type_id = 3 and employee_id = emp.id) as Other
from employee as emp;
but, i think it is not efficient and from every new product_type_id i've to alter this query, can I do this dynamically.
+------------+---------+---------+-------+--+
| Name | Service | Product | Other | |
+------------+---------+---------+-------+--+
| Bezos | 1 | 0 | 0 | |
+------------+---------+---------+-------+--+
| Steve | 0 | 3 | 0 | |
+------------+---------+---------+-------+--+
| Bill gates | 1 | 0 | 0 | |
+------------+---------+---------+-------+--+
| Tim Cook | 0 | 0 | 1 | |
+------------+---------+---------+-------+--+
and
Let this table is Table_2
In this I can't figure out how this is even possible in mysql as there is no pivot feature in mysql.
+------------+---------+---------+---------+---------+-----------+-------+
| Name | Amazon | iPhone | iPad | iPod | Microsoft | IDK |
+------------+---------+---------+---------+---------+-----------+-------+
| Bezos | Service | NULL | NULL | NULL | NULL | NULL |
+------------+---------+---------+---------+---------+-----------+-------+
| Steve | NULL | Product | Product | Product | NULL | NULL |
+------------+---------+---------+---------+---------+-----------+-------+
| Bill gates | NULL | NULL | NULL | NULL | PRODUCT | NULL |
+------------+---------+---------+---------+---------+-----------+-------+
| Tim Cook | NULL | NULL | NULL | NULL | NULL | OTHER |
+------------+---------+---------+---------+---------+-----------+-------+
Please help.
Note : There can be more than 100 items in product_type, employee_products table.
Try this for Table_1
Select name, Max(Service) as Service, Max(Product) as Product, Max(Other) as Other
From (
select e.name,
count(case when ep.product_type_id = 1 then 1 else null end) as Service,
count(case when ep.product_type_id = 2 then 1 else null end) as Product,
count(case when ep.product_type_id = 3 then 1 else null end) as Other,
from employee e
inner join employee_products ep on (e.id = ep.employee_id)
)
Group by name;
Note: same way you can try for Table_2
There are several bits of code out there for dynamically building and running the SELECT with the columns dynamically deduced. Here is mine.

COUNT counting something on LEFT JOIN that doesn't exist. Why?

I'm having a problem.
I have this table called usersbycourse which shows this information:
+------------+-----------------+--------+-----------+-------+-----------------+-----------------+
| instanceid | shortname | userid | firstname | logid | lastaccessdelta | modulesfinished |
+------------+-----------------+--------+-----------+-------+-----------------+-----------------+
| 2 | PJU | 74 | Robin | 766 | 1662246 | 0 |
| 3 | Fundgest-GRHN1A | 75 | Batman | 867 | 1576725 | 0 |
| 3 | Fundgest-GRHN1A | 77 | Abigobeu | 1004 | 610480 | 0 |
+------------+-----------------+--------+-----------+-------+-----------------+-----------------+
and this SQL:
SELECT
mdl_course.id,
mdl_course.shortname,
COUNT(CASE WHEN usersbycourse.modulesfinished = 1 THEN NULL ELSE 1 END) AS studentcount
FROM mdl_course LEFT JOIN usersbycourse ON mdl_course.id = usersbycourse.instanceid
GROUP BY mdl_course.id;
The results from the SQL are:
+----+-----------------+--------------+
| id | shortname | studentcount |
+----+-----------------+--------------+
| 1 | Unity I | 1 |
| 2 | PJU | 1 |
| 3 | Fundgest-GRHN1A | 2 |
| 4 | asdzxc2 | 1 |
+----+-----------------+--------------+
But why? In inside SQL has no Unity I, and no asdzxc2. How do I produce a result like this:
+----+-----------------+--------------+
| id | shortname | studentcount |
+----+-----------------+--------------+
| 1 | Unity I | 0 |
| 2 | PJU | 1 |
| 3 | Fundgest-GRHN1A | 2 |
| 4 | asdzxc2 | 0 |
+----+-----------------+--------------+
?
EDIT:
I want to count only rows having modulesfinished = 0
What you're looking for is SUM rather than COUNT, that is,
SELECT
mdl_course.id,
mdl_course.shortname,
SUM(CASE WHEN usersbycourse.modulesfinished = 0 THEN 1 ELSE 0 END) AS studentcount
FROM mdl_course LEFT JOIN usersbycourse ON mdl_course.id = usersbycourse.instanceid
GROUP BY mdl_course.id;
The problem is because you are using LEFT JOIN some of the values for usersbycourse.modulesfinished are NULL
Something you need to learn is
NULL == something
Is always unknown, not true, not false, just unknown.
So when you try to compare with = 1 your nulls get the ELSE but not because they aren't 1, is because is all the rest.
So if instead you change the condition to
COUNT(CASE WHEN usersbycourse.modulesfinished = 0 THEN 1 ELSE NULL)
Only the TRUE match will get 1, the FALSE and the UNKNOW part ill get NULL and COUNT doesnt count nulls. And that is what you want.

MySQL Data Summary/Counts Table

I'm trying to put together a summary table that has counts of types of mail sent by group.
Hopefully the below is enough to explain what I mean.
Table 1 (senders)
| id | name | group_id |
+----+------+----------+
| 1 | mike | 1 |
| 2 | john | 1 |
| 3 | lucy | 2 |
| 4 | lobo | 3 |
Table 2 (mail)
| id | type | sender_id |
+----+----------+-----------+
| 1 | letter | 1 |
| 2 | postcard | 2 |
| 3 | postcard | 1 |
| 4 | letter | 2 |
| 5 | postcard | 2 |
| 6 | postcard | 4 |
Table 3 (groups)
| id | name | active |
+----+-------+--------+
| 1 | alpha | 1 |
| 2 | black | 1 |
| 3 | cero | 0 |
Ideal result
| group | letter | postcard | parcel |
+-------+--------+----------+--------+
| alpha | 2 | 3 | 0 |
| black | 0 | 0 | 0 |
So I need to get counts per mail type for active groups.
I've been working through examples (only learning MySQL) but when I think of this situation I'm just totally blank.
Have looked at the answers to Joining three tables to get summary data in MySQL but I don't quite understand how to translate the answers to my problem.
Any help is appreciated.
SELECT t.name,
MAX(CASE t.TYPE WHEN 'letter' THEN #CS:=#CS+1 ELSE 0 END ) letter,
MAX(CASE t.TYPE WHEN 'postcard' THEN #CS1:=#CS1+1 ELSE 0 END ) postcard ,
MAX(CASE t.TYPE WHEN 'parcel ' THEN #CS2:=#CS2+1 ELSE 0 END ) parcel
FROM
(SELECT
groups. name,
mail.type
FROM
groups
LEFT JOIN senders ON groups.id = senders.id
LEFT JOIN mail ON senders.id = mail.sender_id ) AS t
,(SELECT #CS:=0) CS ,(SELECT #CS1:=0) CS1 ,(SELECT #CS2:=0) CS2
You put this query
Select count(*) from senders s inner join mail m on s.id = s.sender_id inner join
groups g on s.groups_id = g.id group by m.type

Left join with unique values

I am looking to get all values from first table along with joinned values from second table.
Table 1 is fee_category with fields:
id | Category
1 | A
2 | B
3 | C
4 | D
Table 2 is fee_charge with fields:
id | std_id | particularID | CategoryID | assign | amount
1 | 1 | 1 | 1 | 0 | 1000
2 | 1 | 1 | 2 | 1 | 12000
3 | 1 | 2 | 3 | 0 | 3000
4 | 1 | 2 | 4 | 0 | 10
5 | 2 | 1 | 2 | 0 | 100
6 | 2 | 2 | 3 | 0 | 120
Base table is "fee_category" from which I need all values left joining with "fee_charge" from where I need values or NULL for a particular std_id and particularID
SELECT fee_category.id, fee_category.Category, fee_charge.std_id
, fee_charge.particularID, fee_charge.CategoryID, fee_charge.assign, fee_charge.amount FROM fee_category
LEFT join fee_charge on fee_category.id=fee_charge.CategoryID
where (fee_charge.std_id = 1 OR fee_charge.std_id IS NULL)
AND (fee_charge.particularID = 1 OR fee_charge.particularID IS NULL)
group By fee_category.id
order By fee_charge.assign DESC
Here I am trying to get all categories of std_id=1 and particularID=1
Correct result should be
id | Category | std_id | particularID | CategoryID | assign | amount
1 | A | 1 | 1 | 1 | 0 | 1000
1 | B | 1 | 1 | 2 | 1 | 12000
1 | C | 1 | NULL | NULL | NULL | NULL
1 | D | 1 | NULL | NULL | NULL | NULL
I am trying various versions of the above query but not getting proper result. Please help
SELECT fee_category.id
, fee_category.Category
, X.std_id
, X.particularID
, X.CategoryID
, X.assign
, X.amount
FROM fee_category
LEFT JOIN
(SELECT * FROM fee_charge
WHERE fee_charge.std_id = 1
AND fee_charge.particularID = 1) AS X
ON x.CategoryID = fee_category.id
It's very hard to follow when the fiddle doesn't match the question, so I may have misunderstood, but perhaps you're after something like this...
SELECT x.id
, z.category
, x.std_id
, y.particularID
, y.categoryID
, y.assign
, y.amount
FROM fee_charge x
LEFT
JOIN fee_charge y
ON y.id = x.id
AND y.particularID = 1
JOIN fee_category z
ON z.id = x.categoryID
WHERE x.std_id = 1;