How to use subquery with inner join in MYSQL? - mysql

Do you guys have any idea how to combine this code using subquery. The code works fine but I don't know how to combine it as a one query
SELECT DATE_FORMAT(FROM_DAYS(DATEDIFF(now(),STR_TO_DATE(dob, '%c/%e/%Y'))), '%Y')+0 AS Age
FROM tblpatient
SELECT pres.*,
CONCAT(p.fname,' ',p.lname) AS pname,
p.gender,
p.address
FROM prescription pres
INNER JOIN tblpatient p
WHERE p.id = pres.patient_id
AND pres.id='$user_id' LIMIT 1"

I believe this is what you were expecting, merging both of your queries together.
SELECT pres.*,
CONCAT(p.fname,' ',p.lname) AS pname,
p.gender,
p.address,
DATE_FORMAT(FROM_DAYS(DATEDIFF(now(),STR_TO_DATE(p.dob, '%c/%e/%Y'))), '%Y')+0 AS Age
FROM prescription pres
INNER JOIN tblpatient p
WHERE p.id = pres.patient_id
AND pres.id='$user_id' LIMIT 1"

Related

Multiple aggregate functions in SQL query

For this example I got 3 simple tables (Page, Subs and Followers):
For each page I need to know how many subs and followers it has.
My result is supposed to look like this:
I tried using the COUNT function in combination with a GROUP BY like this:
SELECT p.ID, COUNT(s.UID) AS SubCount, COUNT(f.UID) AS FollowCount
FROM page p, subs s, followers f
WHERE p.ID = s.ID AND p.ID = f.ID AND s.ID = f.ID
GROUP BY p.ID
Obviously this statement returns a wrong result.
My other attempt was using two different SELECT statements and then combining the two subresults into one table.
SELECT p.ID, COUNT(s.UID) AS SubCount FROM page p, subs s WHERE p.ID = s.ID GROUP BY p.ID
and
SELECT p.ID, COUNT(f.UID) AS FollowCount FROM page p, follow f WHERE p.ID = f.ID GROUP BY p.ID
I feel like there has to be a simpler / shorter way of doing it but I'm too unexperienced to find it.
Never use commas in the FROM clause. Always use proper, explicit, standard JOIN syntax.
Next, learn what COUNT() does. It counts the number of non-NULL values. So, your expressions are going to return the same value -- because f.UID and s.UID are never NULL (due to the JOIN conditions).
The issue is that the different dimensions are multiplying the amounts. A simple fix is to use COUNT(DISTINCT):
SELECT p.ID, COUNT(DISTINCT s.UID) AS SubCount, COUNT(DISTINCT f.UID) AS FollowCount
FROM page p JOIN
subs s
ON p.ID = s.ID JOIN
followers f
ON s.ID = f.ID
GROUP BY p.ID;
The inner joins are equivalent to the original query. You probably want left joins so you can get counts of zero:
SELECT p.ID, COUNT(DISTINCT s.UID) AS SubCount, COUNT(DISTINCT f.UID) AS FollowCount
FROM page p LEFT JOIN
subs s
ON p.ID = s.ID LEFT JOIN
followers f
ON p.ID = f.ID
GROUP BY p.ID;
Scalar subquery should work in this case.
SELECT p.id,
(SELECT Count(s_uid)
FROM subs s1
WHERE s1.s_id = p.id) AS cnt_subs,
(SELECT Count(f_uid)
FROM followers f1
WHERE f1.f_id = p.id) AS cnt_fol
FROM page p
GROUP BY p.id;

How can I add multiple tables via LEFT JOIN and count the rows of each table?

I am counting the results of a table I LEFT JOINED:
SELECT p.*,COUNT(po.name) AS posts
FROM projects p
left join posts po on p.name = po.name
group by p.id
http://sqlfiddle.com/#!9/3e9d4b/4
But now I want to add another table via LEFT JOIN and count it also:
SELECT p.*,COUNT(po.name) AS posts,
COUNT(ta.name) AS tasks
FROM projects p
left join posts po on p.name = po.name
left join tasks ta on p.name = ta.name
group by p.id
http://sqlfiddle.com/#!9/ee068/2
But now the counting is wrong. For cat I have only 2 posts and 3 tasks. Where is the number 6 coming from?
Left joins are not the right tool for this. You should use subselects:
SELECT p.*,
(SELECT COUNT(*) FROM posts po WHERE p.name = po.name) AS posts,
(SELECT COUNT(*) FROM tasks ta WHERE p.name = ta.name) AS tasks
FROM projects p
You can still use joins, but instead of a single top level aggregation, you can aggregate each of the two tables in separate subqueries:
SELECT
p.name,
COALESCE(t1.posts_cnt, 0) AS posts_cnt,
COALESCE(t2.tasks_cnt, 0) AS tasks_cnt
FROM projects p
LEFT JOIN
(
SELECT name, COUNT(*) AS posts_cnt
FROM posts
GROUP BY name
) t1
ON p.name = t1.name
LEFT JOIN
(
SELECT name, COUNT(*) AS tasks_cnt
FROM tasks
GROUP BY name
) t2
ON p.name = t2.name
Your current queries have problems, because you are aggregating by id but selecting other columns. From what I see, you want to be aggregating in all three tables using the name column.
This approach should outperform an approach using correlated subqueries.

Joining 3 tables on sql and checking conditions

SelectClassicModels.Orders.CustomerNumber,
ClassicModels.CUSTOMERS.CUSTOMERNAME,
ClassicModels.Employees.LASTNAME,
ClassicModels.Employees.firstNAME,
ClassicModels.employees.EmployeeNumber
from ClassicModels.Orders
join
ClassicModels.Customers
on ClassicModels.Orders.CustomerNumber = ClassicModels.Customers.CUSTOMERNUMBER
join
ClassicModels.EMPLOYEES
on ClassicModels.Employees.EMPLOYEENUMBER = ClassicModels.CUSTOMERS.SalesRepEmployeeNumber
Those three tables when joined work just fine, but when I try and add these modifiers, they don't work
group by ClassicModels.Orders.CustomerNumber
having count(ClassicModels.Orders.CustomerNumber) < 4
First off, welcome to StackOverflow!
I've re-formatted your SQL using my favorite tool, which I can provide a link to if you're interested. I've also added aliases to help make it more "readable". (The aliases are the lowercase bits after the table name in the FROM and JOIN clauses.)
SELECT orders.CustomerNumber,
customers.CustomerName,
employees.LastName,
employees.FirstName,
employees.EmployeeNumber
FROM CLASSICMODELS.ORDERS orders
JOIN CLASSICMODELS.CUSTOMERS customers
ON orders.CustomerNumber = customers.CustomerNumber
JOIN CLASSICMODELS.EMPLOYEES employees
ON employees.EmployeeNumber = customers.SalesRepEmployeeNumber
Now that we've got that done. Let's add your GROUP BY and HAVING clauses.
GROUP BY clauses have to have ALL of the columns used in the SELECT clause in them. (I'm not sure why. I haven't looked it up, but I just know that's how it works. :) )
SELECT orders.CustomerNumber,
customers.CustomerName,
employees.LastName,
employees.FirstName,
employees.EmployeeNumber
FROM CLASSICMODELS.ORDERS orders
JOIN CLASSICMODELS.CUSTOMERS customers
ON orders.CustomerNumber = customers.CustomerNumber
JOIN CLASSICMODELS.EMPLOYEES employees
ON employees.EmployeeNumber = customers.SalesRepEmployeeNumber
GROUP BY orders.CustomerNumber,
customers.CustomerName,
employees.LastName,
employees.FirstName,
employees.EmployeeNumber
Now that should work. Then you just have to add your HAVING clause in there.
SELECT orders.CustomerNumber,
customers.CustomerName,
employees.LastName,
employees.FirstName,
employees.EmployeeNumber
FROM CLASSICMODELS.ORDERS orders
JOIN CLASSICMODELS.CUSTOMERS customers
ON orders.CustomerNumber = customers.CustomerNumber
JOIN CLASSICMODELS.EMPLOYEES employees
ON employees.EmployeeNumber = customers.SalesRepEmployeeNumber
GROUP BY orders.CustomerNumber,
customers.CustomerName,
employees.LastName,
employees.FirstName,
employees.EmployeeNumber
HAVING COUNT(orders.CustomerNumber) < 4
I was also looking over your query, and you might get faster (and more efficient results) by using a query like this:
WITH CUSTOMERSWITHLESSTHANFOURORDERS
AS
(
SELECT CUSTOMERNUMBER
FROM CLASSICMODELS.ORDERS
GROUP BY CUSTOMERNUMBER
HAVING COUNT(CUSTOMERNUMBER) < 4
)
SELECT O.CUSTOMERNUMBER,
C.CUSTOMERNAME,
E.LASTNAME,
E.FIRSTNAME,
E.EMPLOYEENUMBER
FROM CUSTOMERSWITHLESSTHANFOURORDERS O
JOIN CLASSICMODELS.CUSTOMERS C
ON O.CUSTOMERNUMBER = C.CUSTOMERNUMBER
JOIN CLASSICMODELS.EMPLOYEES E
ON E.EMPLOYEENUMBER = C.SALESREPEMPLOYEENUMBER;
It uses what is called "common table expression" and basically just isolates a portion of the query. It could be more efficient because it's going to try and group on less data, so it could be faster. Be wary, because there's lots of "could"'s in there because I don't know how various different things are set up in your MySQL database.
Good luck!

Mysql COUNT sub query

I have a fairly complex query for myself across a few tables that I have nearly finished. The final aspect involves just aggregating how many bids an item has received, I am doing this for all items in a particular section though. The query works fine except it only returns 1 row when I try and add in aggregation (/* */) to the query. Reading around it would seem i need a sub query, except I'm not entirely sure how to go about this. This is the query to date:
SELECT s.id as section_id, s.name as section, i.id as item_id,
i.title as item_title, item.location_id as item_location_id,
i.slug as item_slug, i.description as item_description,
i.price as item_price, UNIX_TIMESTAMP(i.date_added) as item_date_added,
c.id, c.city, c.particular_id, p.id, p.particular /*,COUNT(o.i_id) as interest*/
FROM section as s
INNER JOIN item as i
ON s.id = i.section_id
INNER JOIN city as c
ON i.location_id = c.id
INNER JOIN particular as p
ON c.particular_id = p.id
/*LEFT JOIN offer as o
ON o.job_id = i.id*/
WHERE s.id = 2
The code works in that it returns all the rows I expected until the introduction of the /* */ code, where it now only returns 1 row.
any help you could give me would be appreciated
Thanks
Jonny
You have to have group bys if you are doing aggregates, e.g.:
SELECT s.name, COUNT(i.id)
FROM section as s
INNER JOIN item as i
GROUP BY s.name
would return the section name and the number of items found in it.
It should solve your problem:
SELECT s.id as section_id, s.name as section, i.id as item_id,
i.title as item_title, item.location_id as item_location_id,
i.slug as item_slug, i.description as item_description,
i.price as item_price, UNIX_TIMESTAMP(i.date_added) as item_date_added,
c.id, c.city, c.particular_id, p.id, p.particular,
(SELECT COUNT(o.i_id) FROM offer AS o ON o.job_id = i.id) AS interest
FROM section as s
INNER JOIN item as i
ON s.id = i.section_id
INNER JOIN city as c
ON i.location_id = c.id
INNER JOIN particular as p
ON c.particular_id = p.id
WHERE s.id = 2

MySQL select in join clause scanning too many rows

Oke guys, the following has been bugging me all day:
I use the query below to select an overview of products and prices including the latest result-price based on field StartTime from another table (tresults). To do this I thought I would need a subselect in the join.
The problem is that the EXPLAIN function is telling me that MySQL is scanning ALL result rows (225000 rows) not using any index.
Is there some way I can speed this up? Preferably by adding a WHERE statement to have mysql look only at the rows with the corresponding pID's.
select p.pID, brandname, description, p.EAN, RetailPrice, LowestPrice, min(price), min(price)/lowestprice-1 as afwijking
from tproducts p
join (
select Max(tresults.StartTime) AS maxstarttime, tresults.pID
from tresults
-- maybe adding a where clause here?
group by tresults.pID
) p_max on (p_max.pID = p.pID)
join tresults res on (res.starttime = p_max.maxstarttime and p.pID = res.pID and res.websiteID = 1)
join tsupplierproducts sp on (sp.pID = p.pID AND supplierID = 1)
join tbrands b on (b.brandID = p.BrandID)
group by p.pID, brandname, description, p.EAN, RetailPrice, LowestPrice
Indexes are on all columns that are part of joins or where clauses.
Any help would be appreciated. Thanks!
From your SQL I assume that you are listing product based on 1 supplier (supplierID = 1) only.
Best practice is do your known filter at begin of sql to eliminate record, then use inner join to join other without filter table.
select p.pID, brandname, description, p.EAN, RetailPrice, LowestPrice, min(price), min(price)/lowestprice-1 as afwijking
from
(select p.pID, p.BrandID p.EAN, Max(t.StartTime) AS maxstarttime
FROM tproducts p INNER JOIN tresults t on supplierID=1 and p.pID=t.pID
group by tresults.pID
) p
inner join tresults res on (res.websiteID = 1 and p.pID = res.pID and res.starttime = p_max.maxstarttime)
inner join tsupplierproducts sp on (sp.pID = p.pID)
inner join tbrands b on (b.brandID = p.BrandID)
group by p.pID, brandname, description, p.EAN, RetailPrice, LowestPrice
from above code, I eliminate all supplierID != 1 from tproducts before join tresults.
let me know if the above sql help, and what is the EXPLAIN function result
:-)