Pass value from query 1 to query 2 - mysql

I have a query join 2 table as below:
SELECT * FROM Staff s INNER JOIN Account a on s.AccNo = a.AccNo WHERE a.Status = 'Active'
The result as shown:
AccNo | Name | ID
------------------
1 | Alex | S01
2 | John | S02
After I get the staff ID,I write second query to find out the max sale as below:
SELECT s.ProductID,Max(s.Amount) from Sales s WHERE StaffID = 'S01' GROUP BY s.ProductID
The max sale for Staff 'S01' as below:
ProductID | Amount
------------------
Cloth | 2000
How to I combine these 2 queries and become result as below? Thanks
AccNo | Name | ID | Amount
--------------------------
1 | Alex | S01 | 2000
2 | John | S02 | 5000

You can create a subquery and join it:
SELECT a.AccNo, b.Name, b.ID, c.maximum
FROM transaction as a
INNER JOIN Account as b
ON a.AccNo = b.AccNo
LEFT JOIN (SELECT StaffID, Max(Amount) as maximum FROM Sales GROUP BY StaffID) as c
ON c.StaffID = b.ID
WHERE b.Status = 'Active'
See the SQLFiddle example (I've tried to guess the schema)

So what you want to do is join to sales on the staffId then group.
SELECT a.AccNo,a.Name,a.ID,Max(s.Amount)
FROM Transaction t
INNER JOIN Account a on t.AccNo = a.AccNo
INNER JOIN Sales s on s.staffId = a.ID
WHERE a.Status = 'Active'
GROUP BY a.AccNo,a.Name,a.ID

You could try something like this:
Select Account.*, Max(Sales.amount) from Sales
JOIN Account ON Sales.StaffID = Account.ID
where Account.status = 'Active'
group by Sales.ProductID, Account.AccNo, Account.Name, Account.ID
Honestly, I don't understand why do you use Transascation table in your queries, because you don't use it.

I think this should work
Just do a join and retrieve the max amount associated with each staff
SELECT t.AccNo , t.Name, t.ID, s.ProductID, Max(s.Amount) FROM Transaction t
INNER JOIN Account a ON t.AccNo = a.AccNo
INNER JOIN Sales s ON s.StaffID = a.ID
WHERE a.Status = 'Active';
Thanks

Related

Optimize and reduce size of Union Select Query

My question is about how to optimize and reduce size of a sql query. I want to join more than 20 multiple queries using UNION, it is giving me the correct result as per the below logic, but I am looking for two things here
something more efficient
I already have 20 UNIONS in my query, and every month I have to add 2-4 UNIONS more which make this query very long so is there any way this query can be rephrased with less code
Select
'343' As 'Manual ID',
'24/07/2020' As 'Date',
A.ID,
O.Order_Name,
C.Customer_Name,
Q.Quantity
From Shipper A
Left Join Order O A.ID = O.ID
Left Join Customer C A.ID = C.ID
Left Join Quantity Q Q.ID = C.ID
where A.ID IN (1)
UNION
Select
'323' As 'Manual ID',
'24/08/2020' As 'Date',
A.ID,
O.Order_Name,
C.Customer_Name,
Q.Quantity
From Shipper A
Left Join Order O A.ID = O.ID
Left Join Customer C A.ID = C.ID
Left Join Quantity Q Q.ID = C.ID
where A.ID IN(2,3,4)
and so on ...
Result
Manual ID | Date | Shipper | Order Name | Customer Name | Qty
343 | 24/07/2020 | 1 | order1 | A | 5
323 | 24/08/2020 | 2 | order2 | B | 2
323 | 24/08/2020 | 3 | order3 | C | 1
323 | 24/08/2020 | 4 | order4 | D | 12
You can try this:
Select
CASE
WHEN A.ID IN(1) THEN '343'
WHEN A.ID IN(2,3,4) THEN '323'
END As 'Manual ID',
CASE
WHEN A.ID IN(1) THEN '24/07/2020'
WHEN A.ID IN(2,3,4) THEN '24/08/2020'
END As 'Date',
A.ID,
O.Order_Name,
C.Customer_Name,
Q.Quantity
From Shipper A
Left Join Order O A.ID = O.ID
Left Join Customer C A.ID = C.ID
Left Join Quantity Q Q.ID = C.ID
Where A.ID IN(1,2,3,4)
First suggestion is to move the parameters in to another table, then join on it. You can even make that an inline view if you don't want to use a real table...
Second suggestion is to use UNION ALL to avoid the costs of deduplication incurred by UNION.
SELECT
params.*,
O.Order_Name,
C.Customer_Name,
Q.Quantity
FROM
(
SELECT '343' As 'Manual ID', '24/07/2020' As 'Date', 1 AS A_ID
UNION ALL SELECT '323' As 'Manual ID', '24/08/2020' As 'Date', 2 AS A_ID
UNION ALL SELECT '323' As 'Manual ID', '24/08/2020' As 'Date', 3 AS A_ID
UNION ALL SELECT '323' As 'Manual ID', '24/08/2020' As 'Date', 4 AS A_ID
)
AS params
INNER JOIN Shipper A ON A.ID = params.A_ID
Left Join Order O ON A.ID = O.ID
Left Join Customer C ON C A.ID = C.ID
Left Join Quantity Q ON Q.ID = C.ID
Alternatively, don't recompute this every month. Write a new query each month, and insert the results into another table?
If you just want to go for query the better way would be to use the case when statement but every now and then you need to keep updating the query adding new cases.
Another, optimized solution will be to create a new table to store
Manual ID, Date, (Common) ID present in Shipper (Table). Then create a view to join all above tables with new Table.
New Table
Manual ID | Date | ID |
343 | 24/07/2020 | 1 |
323 | 24/08/2020 | 2 |
323 | 24/08/2020 | 3 |
323 | 24/08/2020 | 4 |
Then Create a View Joining all Tables including new new table with ID.
In this you just need add new value to new table and you will complete result in view it self.
CREATE VIEW MY_VIEW
AS
SELECT * FROM
(
Select
T.[Manual ID],
T.[Date],
A.ID,
O.Order_Name,
C.Customer_Name,
Q.Quantity
From Shipper A
Left Join Order O A.ID = O.ID
Left Join Customer C A.ID = C.ID
Left Join Quantity Q Q.ID = C.ID
Left Join NewTable T T.ID = A.ID
)
Now just insert value in new table and fetch complete data from MY_VIEW. It will give the same result as you are excepting.

Fetch only matching records from two entities

Please help me with the MYSQL query.
Entity Name: OrderItem
Attributes: orderId(PK), orderItemSeqId(PK), productId
Entity Name: ProductFacility
Attributes: facilityId(PK), productId(PK), inventoryCount (Integer)
**OrderId | orderItemSeqId | productId**
OID1 | 0001 | 10000
OID1 | 0002 | 10001
OID1 | 0003 | 10002
**FacilityId | ProductId | InventoryCount**
FC_1 | 10000 | 12
FC_1 | 10001 | 5
FC_1 | 10002 | 7
FC_2 | 10001 | 1
FC_2 | 10002 | 6
FC_3 | 10002 | 7
Here I want to fetch the facility (FC_1) which has all the products available for order.
I don't want the facility records which has partial products (like facility FC_3 has only one (10002) product from order OID1)
I only want the facilityId records which have all the products from the order (ex OID1)
IMPORTANT POINT: This SQL will be executed on millions of records.
Try this:
select *
from ProductFacility f1
where (select count(distinct InventoryCount) cnt_fac
from ProductFacility f2
where f2.FacilityId = f1.FacilityId
and InventoryCount > 0
group by FacilityId ) = (select count(distinct productId)
from OrderItem );
Here is a DEMO
This will get you the facilities you are looking for
with cte as
(
select OrderId, count(*) as c
from orderT a
group by OrderId
)
select FacilityId, b.OrderId, count(*) as c from Facility a
inner join orderT b on a.ProductId = b.ProductId
group by FacilityId, b.OrderId
having count(*) = (select c from cte c where c.OrderId = b.OrderId)
To get a list of which facilities can satisfy an order, you need to check which facility has InventoryCount > 0 for each product in the order, which you can do with this query:
SELECT O.OrderId, F.FacilityID
FROM (SELECT DISTINCT productId
FROM OrderItem) P
CROSS JOIN (SELECT DISTINCT OrderId
FROM OrderItem) O
CROSS JOIN (SELECT DISTINCT FacilityId
FROM ProductFacility) F
LEFT JOIN OrderItem OI ON OI.OrderId = O.OrderID AND OI.productId = P.productId
LEFT JOIN ProductFacility PF ON PF.FacilityId = F.FacilityId AND PF.productId = OI.productId AND PF.InventoryCount > 0
GROUP BY O.OrderId, F.FacilityID
HAVING COUNT(OI.ProductId) = COUNT(PF.ProductId)
I have added an additional order to my demo which requires products 10001 and 10002; for that the output is
OrderId FacilityID
OID1 FC_1
OID2 FC_1
OID2 FC_2
Demo on SQLFiddle
This should work:
select oc.orderId, ofc.facilityId
from
(
select orderId, count(*) productCount
from OrderItem
group by orderId) oc
inner join
(
select pf.facilityId, oi.orderId, count(*) productsAvailableCount
from ProductFacility pf
inner join OrderItem oi on oi.productId = pf.productId and pf.inventoryCount > 0
group by pf.facilityId, oi.orderId
) ofc on ofc.orderId = oc.orderId and oc.productCount = ofc.productsAvailableCount
Demo on DB Fiddle

Using MySQL for relationnal division

I need to execute a query with a relationnal division
What I have : 2 tables with a 3rd table for Many-to-Many relation
=> Meetings have multiple participants and participants can attend multiple meetings
What I need : get the meetings which have at least the given participants
Here a SQL query which do the job :
SELECT
m.meeting_id,
m.name,
m.status
FROM meetings As m
INNER JOIN meetings_participants AS mp ON m.meeting_id = mp.meeting_id
WHERE m.status <> 'temporary'
AND mp.participant_id IN (1, 2)
GROUP BY m.meeting_id
HAVING COUNT(DISTINCT mp.participant_id) >= 2
SQL Fiddle : http://sqlfiddle.com/#!9/8a331d/6/0
Question 1 : is there a way to select what I need without the 'HAVING COUNT...' part ?
Question 2 : and in a second query, I need the meetings with exactly the given participants, how to do it ?
Question 1 : is there a way to select what I need without the 'HAVING
COUNT...' part ?
Yes you can use multiple JOIN's but that isn't a very good solution.because you need a JOIN for every mp.participant_id... The Query you have is much more scalable
Query
SELECT
m.meeting_id
, m.name
, m.status
FROM
meetings AS m
INNER JOIN meetings_participants AS mp1 ON m.meeting_id = mp1.meeting_id AND m.status <> 'temporary' AND mp1.participant_id = 1
INNER JOIN meetings_participants AS mp2 ON m.meeting_id = mp2.meeting_id AND m.status <> 'temporary' AND mp2.participant_id = 2
Result
| meeting_id | name | status |
|------------|-----------|-----------|
| 1 | a meeting | active |
| 5 | e meeting | cancelled |
demo http://sqlfiddle.com/#!9/8a331d/54
Question 2 : and in a second query, I need the meetings with exactly
the given participants
You need to find the COUNT first for every meeting_participants HAVING two records
With
SELECT
meeting_id
FROM
meetings_participants
GROUP BY
meeting_id
HAVING COUNT(*) = 2
And use that within the main query like so.
Query
SELECT
meetings.*
FROM (
SELECT
meeting_id
FROM
meetings_participants
WHERE
participant_id IN(1, 2)
AND
meeting_id IN(
SELECT
meeting_id
FROM
meetings_participants
GROUP BY
meeting_id
HAVING COUNT(*) = 2
)
GROUP BY
meeting_id
HAVING COUNT(*) = 2
)
meetings_participants
INNER JOIN
meetings
ON
meetings_participants.meeting_id = meetings.meeting_id
Result
| meeting_id | name | status |
|------------|-----------|-----------|
| 5 | e meeting | cancelled |
demo http://sqlfiddle.com/#!9/8a331d/46

mysql count related table

Hi everyone I would like to count some entries, but I don't know if is possible to do it with joins. The situation is
I've got a tables
student_profile
Id | Name
---------
1 | Name1
2 | Name2
3 | Name3
student_application where profile_id is related to student_profile.id
Id | profile_id | Data
----------------------
1 2 data1
2 2 data2
3 2 data3
And table student_holiday
Id | app_id | date
-----------------------
1 2 2014-01-01
2 3 2014-02-02
So I'm getting all my student_application's with
Select sa.id, s.name From student_application sa
INNER JOIN student_profile s ON s.id = sa.profile_id
I would like to count how many holidays has a student, but I don't have profile_id in student_holiday table. There I've got app_id, so I can't do Left join student_holiday sh ON sh.app_id = sa.id, this wouldn't give the right number.
here sqlfiddle
Thanks in advance for any help.
SELECT student_profile.ID, student_profile.Name, student_holiday.ID
FROM (student_profile INNER JOIN student_holiday ON student_profile.ID = student_holiday.ID) INNER JOIN student_application ON student_holiday.ID = student_application.ID;
Here you go!!! Match ID in all the table as instructed above which is the key to get holidays.
OR match with profile_id
**SELECT student_profile.ID, student_profile.Name, student_holiday.ID
FROM (student_profile INNER JOIN student_holiday ON student_profile.ID = student_holiday.ID) INNER JOIN student_application ON Trim(student_holiday.ID) =
student_application.profile_id;**
Here is your data with the 3rd table joined:
Select s.name, sa.some_data as application_data,h.some_data as holiday_data
From student_application sa
INNER JOIN student_profile s ON s.id = sa.profile_id
INNER JOIN student_holiday h ON h.app_id = sa.id;
Note this will only return records that have an application with a holiday associated.
Then to count them, we just:
Select s.name, sa.some_data as application_data,count(h.some_data) as holiday_data
From student_application sa
INNER JOIN student_profile s ON s.id = sa.profile_id
INNER JOIN student_holiday h ON h.app_id = sa.id
GROUP BY s.name
Note this answer is based on the fieldnames you used in your sqlfiddle (Data = some_data and date = some_data)

how to write the sql statement?

I have 3 tables as follows in my database. this is used to a application just like foursqure. i need help with the problem of writing the sql statement i have asked in the bottom of this.
thank you
user_details
user_id | fname
----------------
1 | Losh
8 | Dush
9 | Rosh
10 | NELL
friends
user_idf |user_idff
----------------
1 | 8
8 | 9
10 | 1
Check_in
check_in_id |user_id | place | date
--------------------------------------------
1 | 8 | Hotel | 01/01/2012
2 | 9 | Home | 05/01/2012
3 | 1 | Junction | 08/01/2012
4 | 1 | Rest | 11/01/2012
5 | 9 | Hotel | 15/01/2012
6 | 8 | Home | 15/01/2012
i get the user's who are friends with 8 and user 8 details AND the check in places as follows
SELECT a.`user_id`, a.`fname` , b.*
FROM `user_details` a, `check_in` b
WHERE (b.user_id = 8
OR b.user_id in (select user_idf from friends where user_idff = '8' union select user_idff from friends where user_idf = '8')) AND b.user_id = a.user_id
how do i write the sql to select who are friends with 8 and user 8 details AND the last check in place of those users
explanation::
i seeks for a answer such as
user id name place date
1 LOSH Rest 11/01/2012
8 DUSH HOME 15/01/2012
9 ROSH HOTEL 15/01/2012
Join it to the table returned by:
(SELECT `user_id`, `place` FROM Check_in GROUP BY user_id ORDER BY `date` DESC)
That should give you one entry per user, and since it's sorted in reverse by date, that entry should be the most recent.
But when i group by it gives me the first dates not the latest date
How about this:
(SELECT user_id, place
FROM (SELECT * FROM Check_in ORDER BY `date` DESC) tmp
GROUP BY user_id)
SELECT user_id, fname, c.place
FROM user_details u
INNER JOIN (SELECT IF(user_idff = 8, user_idf, user_idff) AS user_id
FROM friends
WHERE (user_idff = 8 OR user_idf = 8)
) f
ON u.user_id = f.user_id
LEFT JOIN (SELECT c1.user_id, place
FROM Check_in c1
LEFT JOIN Check_in c2
ON c1.user_id = c2.user_id AND
c1.date < c2.date
WHERE c2.date IS NULL
) c
ON u.user_id = c.user_id;
This doesn't break ties but it's a straighforward way of answering your question.
EDIT
I just re-read you question and I see that you want user 8 info also. It's not clear whether you want user 8 as a separate row or with info in line with the friends' rows.
select *
from
friends as f inner join check_in as ci on ci.user_id = f.user_idff
inner join user_details as ud on ud.user_id = f.user_idff
inner join user_details as ud8 on ud8.user_id = f.user_idf
where
f.user_idf = 8
and date = (
select max(date)
from friends as f2 inner join check_in as ci on ci.user_id = f2.user_idff
where f2.user_idf = f.user_idf
)
EDIT 2
You request may be a small bit unclear about determining which check-in location to return. Use this option if you want the latest location of each friend individually. The first query finds the most recent location among all friends. Obviously these are two variations on an identical theme.
select *
from
friends as f inner join check_in as ci on ci.user_id = f.user_idff
inner join user_details as ud on ud.user_id = f.user_idff
inner join user_details as ud8 on ud8.user_id = f.user_idf
where
f.user_idf = 8
and date = (
select max(date)
from check_in as ci
where ci.user_id = f.user_idff
)
(SELECT a.user_id, a.place, b.fname, a.date, a.time, a.check_in_id
FROM (SELECT * FROM check_in ORDER BY date DESC) as a, user_details as b
WHERE a.user_id = b.user_id AND (a.user_id in (select user_idf from friends where user_idff = '8' union select user_idff from friends where user_idf = '8') OR a.user_id = 8)
GROUP BY a.user_id)
above query gave me the required answer.
thank you all for the help given