MYSQL: getting min value and group by from two tables [duplicate] - mysql

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 2 years ago.
I have two tables:
Suppliers:
+-------+------+---------------+
| supid | prid | supplier_name |
+-------+------+---------------+
| 2 | 2 | Supplier 1 |
| 3 | 2 | Supplier 2 |
| 4 | 2 | Supplier 3 |
+-------+------+---------------+
Supplier_items:
+-----------+------+-------+--------+------------+
| supitemid | prid | supid | itemid | prod_tcost |
+-----------+------+-------+--------+------------+
| 3 | 2 | 2 | 3 | 6200 |
| 4 | 2 | 2 | 4 | 810 |
| 5 | 2 | 3 | 3 | 5900 |
| 6 | 2 | 3 | 4 | 807 |
| 7 | 2 | 4 | 3 | 6680 |
| 8 | 2 | 4 | 4 | 825 |
+-----------+------+-------+--------+------------+
Please help me to achieve this result getting the min value with supplier_name from Suppliers:
(where prid = 2, group by itemid)
+--------+---------------+----------------+
| itemid | supplier_name | min(prod_tcost) |
+--------+---------------+----------------+
| 3 | Supplier 2 | 5900 |
| 4 | Supplier 2 | 807 |
+--------+---------------+----------------+

You can join and aggregate:
select si.item_id, s.supplier_name, min(si.prod_tcost) min_prod_tcost
from supplier_items si
inner join suppliers s on s.supid = si.supid
where si.item_id in (3, 4) and si.prid = 2
group by si.item_id, s.supid, s.supplier_name

Related

Trouble joining tables

I am trying to make an SQL query that joins three tables and lists a value from two of them.
My current setup is the following:
| Computer(Id) |
|----|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
The harddrives have a unique ID an an associated computer linked by ComputerId
| HardDisk(Id) | HardDisk(ComputerId) |
|---- |-------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 6 |
| 7 | 6 |
| 8 | 7 |
| 9 | 8 |
| 10 | 9 |
Disks have log associated with them. These logs have a unique Id and a HardDiskId which is the disk that the log is associated with
| DiskLog(Id) | DiskLog(HardDiskId) |
|---- |------------|
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 6 | 7 |
| 7 | 6 |
| 8 | 8 |
| 9 | 9 |
| 10 | 10 |
The output I'm looking for is this:
| Computer(Id) | HardDisk(Id) / DiskLog(Id) |
|------------|------------|
| 1 | 1 /1 |
| 2 | 2 / 2 |
| 3 | 3 / 3 |
| 4 | 4 / 4 |
| 5 | 5 / 5 |
| 6 | 7,6 / 6,7 |
| 7 | 8 / 8 |
| 8 | 9 / 9 |
| 9 | 10 / 10 |
I'm trying to get the ComputerId and the associated HardDisk which is found through the DiskLog to be outputted together
I currently have the following query, but it is not working as intended:
SELECT *, group_concat(Computer.Id) Target
from Computer
inner join HardDisk on Computer.Id = HardDisk.ComputerId
inner join DiskLog on HardDisk.Id = DiskLog.Id
group by Computer.Id
Consider the following query:
SELECT
c.Id AS ComputerId,
CONCAT(GROUP_CONCAT(DISTINCT h.Id),
' / ',
GROUP_CONCAT(d.Id)) AS hd_disk_ids
FROM Computer c
LEFT JOIN HardDisk h ON c.Id = h.ComputerId
LEFT JOIN DiskLog d ON d.HardDiskId = h.Id
GROUP BY c.Id;
Demo

SQL Query to join 3 tables, resulting a ordered and sorted list

How can I write a Query to join 3 tables, resulting a ordered and sorted list?

I have 3 tables with the following structure
:
Table Users:
|---------------------------|
| Users |
|---------------------------|
| ID | Name |
|-------------|-------------|
| 1 | John |
|-------------|-------------|
| 2 | David |
|-------------|-------------|
| 3 | James |
|-------------|-------------|
| 4 | Jack |
|-------------|-------------|
Table Questions:
|-------------------------------------------------------|
| Questions |
|-------------------------------------------------------|
| ID | Question |
|-------|-----------------------------------------------|
| 1 | How old are you working in this company? |
|-------|-----------------------------------------------|
| 2 | How many customers do you notice? |
|-------|-----------------------------------------------|
| 3 | What is your salary? |
|-------|-----------------------------------------------|
| 4 | Do you speak another language? |
|-------|-----------------------------------------------|
Table Replies
|----------------------------------------|
| Replies |
|----------------------------------------|
| ID | USER ID | QUESTION ID | Reply |
|-----|---------|-------------|----------|
| 1 | 1 | 1 | 10 |
|-----|---------|-------------|----------|
| 2 | 1 | 2 | 30 |
|-----|---------|-------------|----------|
| 3 | 1 | 3 | 3000 |
|-----|---------|-------------|----------|
| 4 | 1 | 4 | yes |
|-----|---------|-------------|----------|
| 5 | 2 | 1 | 7 |
|-----|---------|-------------|----------|
| 6 | 2 | 2 | 25 |
|-----|---------|-------------|----------|
| 7 | 2 | 3 | 1500 |
|-----|---------|-------------|----------|
| 8 | 2 | 4 | no |
|-----|---------|-------------|----------|
| 9 | 3 | 1 | 5 |
|-----|---------|-------------|----------|
| 10 | 3 | 2 | 50 |
|-----|---------|-------------|----------|
| 11 | 3 | 3 | 2000 |
|-----|---------|-------------|----------|
| 12 | 3 | 4 | yes |
|-----|---------|-------------|----------|
| 13 | 4 | 1 | 7 |
|-----|---------|-------------|----------|
| 14 | 4 | 2 | 40 |
|-----|---------|-------------|----------|
| 15 | 4 | 3 | 2000 |
|-----|---------|-------------|----------|
| 16 | 4 | 4 | yes |
|-----|---------|-------------|----------|
I need to write a SQL Query to filter and sort these results.
Almost like an Excel.


Example:
I need to select who speaks another language, who serves from 5 to 100 clients, ordering for the decreasing salary and years in the descending company.

It should result like this:
|--------------------------------------------------------------------|
| Result |
|--------------------------------------------------------------------|
| ORDER | NAME | QUESTION 1 | QUESTION 2 | QUESTION 3 | QUESTION 4 |
|-------|--------|------------|------------|------------|------------|
| 1 | John | 10 | 30 | 3000 | Yes |
|-------|--------|------------|------------|------------|------------|
| 2 | Jack | 7 | 40 | 2000 | Yes |
|-------|--------|------------|------------|------------|------------|
| 3 | James | 5 | 50 | 2000 | Yes |
|-------|--------|------------|------------|------------|------------|
Any suggestions?
Thanks
Do the JOIN with conditional aggregation :
select u.user_id, u.name,
max(case when r.QUESTIONID = 1 then r.reply) as QUESTION1,
max(case when r.QUESTIONID = 2 then r.reply) as QUESTION2,
max(case when r.QUESTIONID = 3 then r.reply) as QUESTION3,
max(case when r.QUESTIONID = 4 then r.reply) as QUESTION4
from Replies r inner join
Users u
on u.user_id = r.user_id
group by u.user_id, u.name;
EDIT :
select t.*
from ( <query> ) t
where . . .;

MySQL how to find averages / day for different clients with different creation days

I've tried the following queries but unfortunately they don't work :(.
Worth mentioning that each customer has more than one CustomerUsers
select (a.TotalJobs / b.DaysActive) from
(select count(jr.id) as TotalJobs
from jobrequests jr, customers c, customerusers cu
where jr.customeruserid=cu.id
and cu.customerid=c.id
group by c.name) as a,
(select datediff(curdate(), from_unixtime(c.CreationTime)) as DaysActive
from customers c
group by c.name) as b
Please see below the tables
Jobs:
+----+--------------+
| ID | JobRequestID |
+----+--------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 2 |
| 7 | 2 |
| 8 | 3 |
| 9 | 3 |
| 10 | 3 |
| 11 | 4 |
| 12 | 4 |
| 13 | 5 |
| 14 | 5 |
| 15 | 6 |
| 16 | 7 |
| 17 | 8 |
| 18 | 8 |
| 19 | 9 |
| 20 | 10 |
+----+--------------+
JobRequests:
+----+---------------+
| ID | CustomeUserID |
+----+---------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 2 |
| 4 | 2 |
| 5 | 2 |
| 6 | 3 |
| 7 | 4 |
| 8 | 4 |
| 9 | 4 |
| 10 | 5 |
| 11 | 5 |
| 12 | 5 |
| 13 | 6 |
| 14 | 6 |
| 15 | 7 |
+----+---------------+
CustomerUsers:
+----+------------+
| ID | CustomerID |
+----+------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 2 |
| 5 | 2 |
| 6 | 2 |
| 7 | 2 |
| 8 | 3 |
| 9 | 3 |
| 10 | 4 |
+----+------------+
Customers:
+----+------+--------------+
| ID | Name | CreationTime |
+----+------+--------------+
| 1 | a | 1415814194 |
| 2 | b | 1415814194 |
| 3 | c | 1415986994 |
| 4 | d | 1415986994 |
+----+------+--------------+
For the moment it returns 16 results (4X4), dividing each result from 1st sub-query to each result from the 2nd one (each of these sub-queries return 4 results). Can anyone please help me to get this to divide only 1 result from sub-query 1 to it's corespondent from sub-query 2?
Thank you in advance.
I suspect that you can do what you want this a query like this:
select c.name, count(*) / (datediff(curdate(), from_unixtime(c.CreationTime))
from customerusers cu join
jobrequests jr
on jr.customeruserid = cu.id join
customers c
on cu.customerid = c.id
group by c.name;
I don't see why you need two subqueries for this.
I'm guessing you need to join your results together -- as currently written, you're producing a cartesian product.
Try something like this adding c.id to each subquery (it's better to group by it presumably rather than the name):
select (a.TotalJobs / b.DaysActive)
from (
select c.id,
count(jr.id) as TotalJobs
from jobrequests jr
join customers c on jr.customeruserid=cu.id
join customerusers cu on cu.customerid=c.id
group by c.id) a join (
select c.id,
datediff(curdate(), from_unixtime(c.CreationTime)) as DaysActive
from customers c
group by c.id) b on a.id = b.id
Please note, I've updated your syntax to use the more standard join syntax.

Calculate percentage for an area of study

I need help for generating a SQL for MySQL database.
I have two tables:
Students
student_Subjects
Students table:
+------------+---------+-----------------+
| id | name |area_of_study_id |
+------------+---------+-----------------+
| 1 | AAA | 1 |
| 2 | BBB | 2 |
| 3 | CCC | 1 |
| 4 | DDD | 3 |
| 5 | EEE | 4 |
| 6 | FFF | 1 |
| 7 | GGG | 2 |
| 8 | III | 1 |
+------------+---------+-----------------+
student_subjects table:
+------------+-------------------+------------------+
| id | student_id | subject_id |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 1 | 3 |
| 4 | 1 | 2 |
| 5 | 3 | 1 |
| 6 | 6 | 1 |
| 7 | 7 | 3 |
| 8 | 4 | 6 |
+------------+-------------------+------------------+
I need to find out a subject's area of study based on students area of study. From above students table you can see that students have the freedom to choose the area of study. Sometimes, they can choose subjects which are not related to their area of study. So, in this case, we need to calculate area of study for a subject based on the student percentages who have taken the subjects.
Partial output:
+------------+-------------------+-----------------------------------+
|Total_students | subject_id |area_of_study_id | percentage |
+------------+-------------------+-----------------+-----------------+
| 3 | 1 | 1 | 75 |
| 1 | 1 | 2 | 25 |
| 1 | 3 | 1 | 50 |
| 1 | 3 | 2 | 50 |
| 1 | 2 | 1 | 100 |
| 1 | 6 | 3 | 100 |
+------------+-------------------+-----------------+-----------------+
From above partial output, we can see, 3 students choose a subject(i.e subject_id =1) have the area of study 1 and one student is from different area of study (i.e 2). So, we can say subject_id =1 is from area of study = 1.
if percentage 50% for a subject. we can choose any area of study between two, no matter which one.
Expected output:
+------------+-------------------+-----------------------------------+
|Total_students | subject_id |area_of_study_id | percentage |
+------------+-------------------+-----------------+-----------------+
| 3 | 1 | 1 | 75 |
| 1 | 3 | 1 | 50 |
| 1 | 2 | 1 | 100 |
| 1 | 6 | 3 | 100 |
+------------+-------------------+-----------------+-----------------+
Try it this way
SELECT subject_id, area_of_study_id, total_students, percentage
FROM
(
SELECT p.subject_id, p.area_of_study_id, p.total_students,
p.total_students / t.total_students * 100 percentage
FROM
(
SELECT COUNT(*) total_students, ss.subject_id, s.area_of_study_id
FROM students s JOIN student_subjects ss
ON s.id = ss.student_id
GROUP BY ss.subject_id, s.area_of_study_id
) p JOIN
(
SELECT ss.subject_id, COUNT(*) total_students
FROM students s JOIN student_subjects ss
ON s.id = ss.student_id
GROUP BY ss.subject_id
) t ON p.subject_id = t.subject_id
ORDER BY percentage DESC
) q
GROUP BY subject_id;
Output:
| SUBJECT_ID | AREA_OF_STUDY_ID | TOTAL_STUDENTS | PERCENTAGE |
|------------|------------------|----------------|------------|
| 1 | 1 | 3 | 75 |
| 2 | 1 | 1 | 100 |
| 3 | 1 | 1 | 50 |
| 6 | 3 | 1 | 100 |
Here is SQLFiddle demo

How to return row of sum()s

I now find my original table structure was not good, so want to change it.
But I am having a hard time designing queries to obtain totals in rows with the new structure.
current structure:
+----------+-------+-------+-------+-------+
| state | shop | item0 | item1 | item2 |
+----------+-------+-------+-------+-------+
| 5 | 0 | 1 | 2 | 3 |
| 5 | 1 | 1 | 2 | 3 |
| 5 | 2 | 1 | 2 | 3 |
| 4 | 3 | 1 | 2 | 3 |
+----------+-------+-------+-------+-------+
(quantities of items at shop)
I want to change to these 2 tables:
shops table
+---------+--------+
| shop_id | state |
+---------+--------+
| 0 | 5 |
| 1 | 5 |
| 2 | 5 |
| 3 | 4 |
+---------+--------+
items table
+------------+--------------+
| shop | item | quantity |
+------------+--------------+
| 0 | 0 | 1 |
| 0 | 1 | 2 |
| 0 | 2 | 3 |
| 1 | 0 | 1 |
| 1 | 1 | 2 |
| 1 | 2 | 3 |
| 2 | 0 | 1 |
| 2 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 0 | 1 |
| 3 | 1 | 2 |
| 3 | 2 | 3 |
+------------+--------------+
The old layout allowed simple queries for getting totals by row:
SELECT state,SUM(item0) t0,SUM(item1) t1,SUM(item2) t2
FROM shops
WHERE state=5
+--------+---------+---------+----------+
| state | t0 | t1 | t2 |
+--------+---------+---------+----------+
| 5 | 3 | 6 | 9 |
+--------+---------+---------+----------+
With the new structure,
I can get the totals in column as follows:
SELECT item,SUM(quantity) total
FROM shops
LEFT JOIN items ON shop=shopid
WHERE state=5
GROUP by item
+--------+---------+
| item | total |
+--------+---------+
| 0 | 3 |
+--------+---------+
| 1 | 6 |
+--------+---------+
| 2 | 9 |
+--------+---------+
but how do I get the totals in rows:
+--------+---------+---------+----------+
| state | t0 | t1 | t2 |
+--------+---------+---------+----------+
| 4 | 1 | 2 | 3 |
| 5 | 3 | 6 | 9 |
+--------+---------+---------+----------+
You might try using a few more JOINs:
SELECT S.state,
SUM(T0.quantity) AS "T0",
SUM(T1.quantity) AS "T1",
SUM(T2.quantity) AS "T2"
FROM shops AS S
LEFT JOIN items AS T0 ON S.shop_id = T0.shop_id AND T0.item=0
LEFT JOIN items AS T1 ON S.shop_id = T1.shop_id AND T1.item=1
LEFT JOIN items AS T2 ON S.shop_id = T2.shop_id AND T2.item=2
GROUP BY S.state
There might be an easier way.