Mysql group by and prefered field = 1 in join table - php

I have workshops that have manufacturers, one workshop can have many manufacturers, but only one official. I want to get all workshops that have manufacturer 22 but if they have same vat only get workshop who manufacturer is offical
I have 2 tables, first workshop
id | name | vat
-------------------------
1 | name 1 | B12
2 | name 2 | B12
3 | name 3 | B12
4 | name 4 | E98
5 | name 5 | A99
second workshop_manufacturer
id | workshop_id | manufacturer_id | official
----------------------------------------------
1 | 1 | 22 | 0
2 | 2 | 22 | 0
3 | 3 | 22 | 1
4 | 4 | 22 | 0
5 | 5 | 22 | 1
5 | 5 | 23 | 0
5 | 5 | 24 | 0
I want to get unique workshops (group by vat) but I want to get the official one (official=1) if there are many workshop with same vat who work with this manufacturer.
If I do this query:
SELECT t1.*,t2.* FROM workshop t1
INNER JOIN workshop_manufacturer t2 ON t1.id=t2.workshop_id
WHERE t2.manufacturer.id = 22
GROUP bY t1.vat
I get this:
id | name | vat | official | manufacturer_id
-----------------------------------------------
1 | name 1 | B12 | 0 | 22
4 | name 4 | E98 | 0 | 22
5 | name 5 | A99 | 1 | 22
and I want this:
id | name | vat | official | manufacturer_id
-----------------------------------------------
3 | name 3 | B12 | 1 | 22
4 | name 4 | E98 | 0 | 22
5 | name 5 | A99 | 1 | 22
All the workshops who are official and non official but giving priority that ones who are official

This is a prioritization, not an aggregation. But it is rather complicated.
The following gets the ids for the workshops for each "vat":
select w.vat, max(case when w.official = 1 then w.id end) as official_id,
max(w.id) as max_id
from workshop_manufacturer wm join
workshop w
on w.id = wm.workshop_id
group by w.vat;
There are two ids, one if official is available, and another for the maximum id.
You can now use this in a join to get the rest of the fields:
select w.workshop_id, w.name, w.vat,
(official_id is not null) as official
from (select w.vat, max(case when w.official = 1 then w.id end) as official_id,
max(w.id) as max_id
from workshop_manufacturer wm join
workshop w
on w.id = wm.workshop_id
group by w.vat
) v join
workshop w
on w.id = coalesce(official_id, max_id);

Try this.
SELECT t1.*,t2.* FROM workshop t1
INNER JOIN workshop_manufacturer t2 ON t1.id=t2.workshop_id
GROUP bY t1.vat having t2.official = 1

Related

I want to display a summary like this based on the three tables

My 3 MYSQL tables are as follows:
Table 1: citizen
=============================
ID | Name | Sex | Address |
=============================
5 | James | Male | India
6 | Shella|Female | India
7 | Jan | Male | NY
8 | May | Female | USA
==============================
Table 2: benefits
==========================
ID| benefits
==========================
1 | SSS
2 | Coco Life
3 | PhiHealth
4 | Sunlife
==========================
Table 3: pensioners
============================
ID| benefits_ID | citizen_ID
============================
1 | 1 | 5
2 | 2 | 6
3 | 1 | 7
4 | 4 | 7
==========================
I want to display that looks like this:
====================================================================
Address | Total Citizen | Male | Female | SSS | Coco Life | Others |
====================================================================
India | 2 | 1 | 1 | 1 | 1 | 0 |
NY | 1 | 1 | 0 | 1 | 0 | 1 |
USA | 1 | 0 | 1 | 0 | 0 | 0 |
==================================================================
Anybody can give me a hint on how to do this?
You can do a Left Join from the Address table to the benefits table, via pensioners table, using the appropriate relationships. Left join will allows us to consider a Address even when there is no corresponding benefits entry for any of its citizens.
In order to count total citizens, male count and female count, you now need to use COUNT(DISTINCT ID) after the join. As Joining may create duplicate rows, as a citizen may have more than one benefits.
Also, in order to count "Other" benefits, we need to ensure that the benefit IS NOT NULL and it is NOT IN ('SSS', 'Coco Life').
In multi-table queries, it is advisable to use Aliasing for Code clarity (readability) and avoiding ambiguous behaviour.
SELECT
c.Address,
COUNT(DISTINCT CASE WHEN c.Sex = 'Male' THEN c.ID END) AS male_cnt,
COUNT(DISTINCT CASE WHEN c.Sex = 'Female' THEN c.ID END) AS female_cnt,
COUNT(DISTINCT c.ID) AS total_citizen_cnt,
COUNT(CASE WHEN b.benefits = 'SSS' THEN 1 END) AS SSS_cnt,
COUNT(CASE WHEN b.benefits = 'Coco Life' THEN 1 END) AS Coco_Life_cnt,
COUNT(CASE WHEN b.benefits IS NOT NULL AND
b.benefits NOT IN ('SSS', 'Coco Life') THEN 1 END) AS Others_cnt
FROM citizen AS c
LEFT JOIN pensioners AS p
ON p.citizen_ID = c.ID
LEFT JOIN benefits AS b
ON b.ID = p.benefits_ID
GROUP BY c.Address

MySQL pivot to make a row into a colum

I have three tables, products, customers, order
Product:
id | name |
1 | milk |
2 | bread|
3 | Pea |
Customer:
id | name | category
1 | James | retailer
2 | Paul | vendor
3 | Dave | retailer
Order:
id | product_id | customer_id | qty | price
1 | 1 | 2 | 23 | 50
2 | 2 | 2 | 4 | 30
3 | 3 | 2 | 6 | 10
4 | 2 | 1 | 9 | 30
5 | 3 | 1 | 2 | 10
6 | 1 | 3 | 6 | 50
7 | 3 | 3 | 7 | 10
When i do a query to show transactions by customers with category of vendor like
SELECT customer.name, product.name as pname, order.qty, order.price FROM customer, product, order
WHERE customer.id = order.customer_id
AND product.id = order.product_id AND customer.category = "vendor"
i will get something like:
name | pname | qty | price
Paul | milk | 23 | 50
Paul | bread | 4 | 30
Paul | pea | 6 | 10
I want this instead:
name | milk | bread | pea | total
Paul | 23 | 4 | 6 | 90
While that of retailers will look like this:
SELECT customer.name, product.name as pname, order.qty, order.price FROM
customer, product, order
WHERE customer.id = order.customer_id
AND product.id = order.product_id AND customer.category = "retailer"
I will get a table like this:
name | pname | qty | price
James | bread | 9 | 30
James | pea | 2 | 10
Dave | milk | 6 | 50
Dave | pea | 7 | 10
But i want this instead:
name | milk | bread | pea | total
James | 0 | 9 | 2 | 40
Dave | 6 | 0 | 7 | 60
Simply use conditional aggregation for pivoting columns. And be sure to use explicit joins instead of the deprecated implicit join as former has been the standard for 25 years in ANSI-92.
SELECT c.name,
SUM(CASE WHEN p.name = 'milk' THEN o.qty ELSE 0 END) as milk,
SUM(CASE WHEN p.name = 'bread' THEN o.qty ELSE 0 END) as bread,
SUM(CASE WHEN p.name = 'pea' THEN o.qty ELSE 0 END) as pea,
SUM(o.price) AS Total
FROM `customer` c
INNER JOIN `order` o
ON c.id = o.customer_id
INNER JOIN `product` p
ON p.id = o.product_id
WHERE c.category = 'vendor' -- same for retailer
GROUP BY c.name
I think that you cannot have this response structure directly from one simple select
name | milk | bread | pea | total
James | 0 | 9 | 2 | 40
Dave | 6 | 0 | 7 | 60
because your database is getting one row foreach retailers/customer order.
I know that using a server language like PHP or Java you will can handle the data and retrive like you want.

How to group or marge SQL rows via PHP after query

I have a MySQL table like bellow
id | roll | exam_id | course_id | marks | status
----------------------------------------------------------
1 | 01001 | 1 | 1 | 56 | 1
2 | 01002 | 1 | 1 | 68 | 1
3 | 01003 | 1 | 1 | 55 | 1
4 | 01004 | 1 | 1 | 67 | 1
5 | 01001 | 1 | 2 | 54 | 1
6 | 01002 | 1 | 2 | 59 | 1
7 | 01003 | 1 | 2 | 62 | 1
8 | 01004 | 1 | 2 | 63 | 1
9 | 01001 | 2 | 3 | 61 | 1
10 | 01002 | 2 | 3 | 48 | 1
11 | 01003 | 2 | 3 | 22 | 1
12 | 01004 | 2 | 3 | 39 | 1
Now I want to have all the row with exam_id = 1
SELECT * FROM result WHERE exam_id=1 ORDER BY course_id
After that I need to display this table inside HTML after grouping it by roll means one row for each roll that have row-span according to the course number of the result table
Roll | course_id | marks
-----------------------------
01001 | 1 | 56
| 2 | 68
-----------------------------
01002 | 1 | 55
| 2 | 67
-----------------------------
01003 | 1 | 55
| 2 | 62
-----------------------------
01004 | 1 | 67
| 2 | 63
I'm using Codeigniter framework to doing this project. Any suggestions about how I can I do this?
Thank you in advance.
[EDIT]
Current SQL I'm using to do this:
SELECT * FROM `exam_result` JOIN `course` ON `course`.`course_tab_id`=`exam_result`.`result_course` WHERE `exam_id` = '1' AND `result_status` = 1 GROUP BY `exam_result`.`exam_roll`, `course`.`course_tab_id` ORDER BY `exam_result`.`exam_roll` ASC, `course`.`course_id` ASC
Try this but the difference in this table on my first query is that the course title will be included on a single table, I have set the marks as AVG due to so if ever you have duplicate data you will see their average result for the course and roll of a school or whatever you use this structure for
SELECT roll, exam_id, a.course_id, marks, status, course_title, course_credit
FROM
(SELECT roll, exam_id, course_id, AVE(marks) as marks, status FROM result) as a
LEFT JOIN
(SELECT course_id, course_title, course_credit FROM course) as b
ON
a.course_id = b.course_id
WHERE exam_id = '1' -- you can remove this if you wanted all exam appear on your list
GROUP BY roll, exam_id, a.course_id, marks, status, course_title, course_credit
ORDER BY roll, course_id, marks
Try this sql query
SELECT Roll, course_id, AVG(marks)
FROM result WHERE exam='1'
GROUP BY Roll, course_id
ORDER BY roll, course_id, marks

MySql Query for one to many relationship

Facing issue in mysql query, tried with mysql join but not getting expected output.
I want all class, all student record with total ratingscore.Each Class has Many Student. Student has Many or none scholarship
Class table looks like this
+---------------------+
| id classname |
+---------------------+
| 1 10 |
| 2 11 |
| 3 12 |
+---------------------+
Student table looks like, classid is foreign key
+------------------------------------+
| id classid studentname |
+------------------------------------+
| 1 1 xembine |
| 2 1 denial |
| 3 2 suzone |
| 4 3 rosh |
| 5 2 broad |
| 6 1 bell |
| 7 3 martin |
| 8 1 jroff |
+------------------------------------+
rating table looks like, studentid is foreign key
+------------------------------------+
| id studentid ratingscore |
+------------------------------------+
| 1 1 4000 |
| 2 1 10000 |
| 3 5 20000 |
| 4 2 1000 |
| 5 6 2222 |
| 6 1 5000 |
| 7 6 12000 |
| 8 3 3800 |
| 9 5 7500 |
+------------------------------------+
Here : No student from class 3, got any ratingscore yet.so need that student has zero ratingscore.
Expected Output:-
+-------------------------------------------------------------+
| studentname studentid classid classname ratingscore |
+-------------------------------------------------------------+
| xembine 1 1 10 19000 |
| denial 2 1 10 1000 |
| suzone 3 2 11 3800 |
| rosh 4 3 12 0 |
| broad 5 2 11 27500 |
| bell 6 1 10 2222 |
| martin 7 3 12 0 |
| jroff 8 1 10 0 |
+-------------------------------------------------------------+
select s.studentname, s.id as studentid,s.classid,c.classname,sum(ifnull(r.ratingscore,0)) as ratingscore from student s
join class c on c.id=s.classid
left outer join rating r on r.studentid=s.id
group by s.studentname,r.studentid,s.classid,c.classname
Have you try this ?
SELECT s.studentname, s.studentid, c.classid, c.classname, SUM(r.ratingscore)
FROM student as s
INNER JOIN class c on c.classid = s.classid
LEFT OUTER JOIN ratingscore rs ON s.studentid = rs.studentid
GROUP BY s.studentname, s.studentid, c.classid, c.classname
ORDER BY s.studentid
If there is student without class, you have to change inner join to left outer join
SELECT s.studentname AS studentname, s.id AS studentid, c.id AS classid, c.classname AS classname, SUM(r.ratingscore) AS ratingscore
FROM student AS s
INNER JOIN class AS c ON c.id = s.classid
LEFT JOIN rating r ON r.studentid = s.id
GROUP BY s.id
ORDER BY s.id

Row count MySQL with three tables

My MySQL DB looks like this
**table_schools**
id | name
1 | school_1
2 | school_2
**table_classes**
id | class | school_id
1 | a | 1
2 | b | 1
3 | c | 2
4 | d | 2
5 | e | 2
**table_students**
id | name | class_id
1 | Nick | 1
2 | Tom | 2
3 | Kevin | 3
4 | Jane | 4
5 | Mark | 5
6 | Tim | 5
7 | Lynn | 5
I would like to have an output like this:
school_name | class_count | student_count
school_1 | 2 | 2
school_2 | 3 | 5
Is there a way to do this in ONE sql query? And how?
SELECT s.name, COUNT(DISTINCT c.id) AS classes, COUNT(st.id) AS students
FROM table_schools s
LEFT JOIN
table_classes c
ON c.school_id = s.id
LEFT JOIN
table_students st
ON st.class_id = c.id
GROUP BY
s.id
SELECT table_schools.name, COUNT(table_classes.name) AS classes, COUNT(table_students.id) AS students
FROM table_schools
LEFT JOIN table_classes ON table_schools.id = table_classes.school_id
LEFT JOIN table_students ON table_students.class_id = table_classes.id
GROUP BY table_schools.id, table_classes.id
ORDER BY table_schools.name

Categories