I have three tables, tblPresents, tblPresentsOrdered and tblPresentsDelivered.
What I want to do is sum up all the orders and deliveries for a given present ID, so I can tally up the total ordered and delivered and check for discrepancies.
So far I have the following:
$sql ='SELECT prsName, SUM(ordQuantity) AS qtyOrdered,
SUM(delQuantity) AS qtyDelivered
FROM tblPresentOrders
LEFT JOIN tblPresentDeliveries
ON tblPresentDeliveries.delPresent = tblPresentOrders.ordPresent
RIGHT JOIN tblPresents ON tblPresents.prsID = tblPresentOrders.ordPresent
GROUP BY prsName';
The first column (Ordered) is summing up correctly, but the deliveries is counting the delivery twice (there are two separate orders for that line).
What am I doing wrong?
Because you can have multiple orders per delivery (and presumably multiple presents per order) you need to perform aggregation in derived tables before JOINing to avoid duplication in counted/summed values. Note that using a mixture of LEFT JOIN and RIGHT JOIN in the same query can be a bit hard to read so I've rewritten the query using only LEFT JOINs.
SELECT p.prsName, o.qtyOrdered, d.qtyDelivered
FROM tblPresents p
LEFT JOIN (SELECT ordPresent, SUM(ordQuantity) AS qtyOrdered
FROM tblPresentOrders
GROUP BY ordPresent) o ON o.ordPresent = p.prsID
LEFT JOIN (SELECT delPresent, SUM(delQuantity) AS qtyDelivered
FROM tblPresentDeliveries
GROUP BY delPresent) d ON d.delPresent = p.prsID
Related
I'm currently having an issue where I run a query on multiple tables getting the results, but they are all being considered independent. I've tried a couple ways of combining them, but because my SQL knowledge is limited I can't seem to get what I want to happen.
SELECT DISTINCT t.*, s.quantity, s.rrp, ts.thumbnail, ts.bigpic, t.rating
FROM tyres t
INNER JOIN stocklevels s
ON t.stockcode = s.stockcode
LEFT JOIN tyre_treads ts
ON t.treadid = ts.recid
LEFT JOIN reseller r
ON s.city=r.recid
WHERE s.quantity> 0 AND s.rrp > 0
I've tried adding GROUP BY t.recid and a couple other basic solutions but this doesn't seem to work. I've added a couple images which might help.
As you can see the bottom Toyo tyres are the same, just with varying cities and quantities.
Here they are on the website.
I'm wanting to combine they so that they say minimum 6 in stock and shows only once on the site.
As long as there is at least one column in your SQK resukt, which contains different values (like city in your example for "the same" tire, group by won't work. You must adapt your SQL statement in a way, that it only picks columns with the same values. Especially, you should remove the t.* from your sql and name all columns (You then will not need the distinct anymore).
Then, you sum over quantity to get the combined value for this column as wanted.
SELECT r.recid, sum(s.quantity), s.rrp, ts.thumbnail, ts.bigpic, t.rating
FROM tyres t
INNER JOIN stocklevels s
ON t.stockcode = s.stockcode
LEFT JOIN tyre_treads ts
ON t.treadid = ts.recid
LEFT JOIN reseller r
ON s.city=r.recid
WHERE s.quantity> 0 AND s.rrp > 0
GROUP BY recid
Ok, I have a slightly complicated MySQL query
SELECT
childcare_attendance.supplier_id,
suppliers.name As `Childcare Provider`,
Count(families.ufi) As Attended,
families.ufi
FROM
childcare_attendance
LEFT OUTER JOIN
suppliers ON suppliers.id = childcare_attendance.supplier_id
LEFT OUTER JOIN
clients ON childcare_attendance.client_id = clients.id
LEFT OUTER JOIN
families ON clients.family_id = families.id
WHERE
childcare_attendance.trashed <> 1
GROUP BY
childcare_attendance.supplier_id, families.ufi
My issue is I want to create a report that lists the number of unique families that are attending each of the childcare places. I assumed that the above query would perform the task, although the childcare providers are showing multiple times and I am unsure why.
EDIT
Here is a SQL Fiddle without data (I will work on getting some test data in there)
http://sqlfiddle.com/#!9/7ef8e8
I am trying to work out the percentage of a number of students who meet certain criteria.
I have 3 separate tables that I need to get data from, and then I need to get the total from one table (student) as the total of students.
Then I need to use this total, to divide the COUNT of the no of students in the 2nd query.
So basically I am trying to get a count of ALL the students that are in the DB first.
Then count the no of students that appear in my main query (the one returning the data).
Then I need to perform the calculation that will take the noOfStudents (2) and divide by the main total (24) (no of students in DB) then *100 to give me the percentage of students who have met the criteria in the main query.
This is what I have so far:
SELECT * FROM (
(
SELECT s.firstname, s.lastname, s.RegistrationDate, s.Email, d.ReviewDate,(r.description) AS "Viva" , COUNT(*) AS "No of Students"
FROM student s
INNER JOIN dates d
ON s.id=d.student_identifier
INNER JOIN reviews r
ON d.review_Identifier=r.id
WHERE r.description = "Viva Date"
GROUP BY s.student_identifier
ORDER BY s.student_identifier)
) AS Completed
WHERE Completed.ReviewDate BETWEEN '2012-01-01' AND '2014-12-01'
;
I need to output the fields following the second SELECT and this data in turn will be displayed via PHP/HTML code on a page (the BETWEEN dates will be sent via '%s').
I wondered if I should be using 2 separate queries and then getting the value (24) from the first query to perform the calculation in the second query, but I have not been able to work out how to save as 2 separate queries and then reference the first query.
I am also not sure if it is possible to display an overall % total at the same time as outputting the individual rows that meet the criteria?
I am trying to teach myself SQL, so I apologise if I have made any glaring mistakes/assumptions in any of the above, and would appreciate any advice that's out there.
Thank you.
Could you do this?
SELECT COUNT(*) as TotalPopulation,
COUNT(d.student_identifier='student') as TotalStudents,
COUNT(d.student_identifier='student')/ count(*) *100 as Percentage of students
from students s
inner join dates d
on s.id = d.student_identifier
inner join reviews r
on r.id = d.review_Identifier
WHERE d.ReviewDate BETWEEN '2012-01-01' AND '2014-12-01' and r.description = 'Viva Date';
You do not need first name last name if you are just looking for counts, necessarily.
This get's the count(*) of table, then whatever flag you use to identify a student in the second count(), you just had it grouped by before, which could give you wrong results considering there's much else in your select before aggregation.
You could also try:
SELECT d.student_identifier, s.firstname, s.lastname,
s.RegistrationDate, s.Email, d.ReviewDate,(r.description) AS "Viva"
FROM student s
INNER JOIN dates d
ON s.id=d.student_identifier
INNER JOIN reviews r
ON d.review_Identifier=r.id
WHERE r.description = "Viva Date" and d.ReviewDate BETWEEN '2012-01-01' AND '2014-12-01'
ORDER BY s.student_identifier
Now, if you want to return a list, that's the second one, if you want to return a count, you would use the first query and adjust to your student_identifier.
I have two tables with following fields:
...
orders.orderID
orders.orderValue
and
payments.orderID
payments.payVal
In payments.payVal there will be incremental payments for each order (many-to-one).
What I need it so select ALL orders from orders where there is payment left (orders.orderValue - ((sum)payments.payVal) > 0 ).
The only thing I can come up to right now is a (foreach) using the orderID, but I cannot do that for some particular reasons. I also cannot add a column inside table to hold the value for some reasons too.
What I need, is to perform the entire selection in one single SQL Query something that resembles this idea: SELECT * FROM orders WHERE <... each(orderValue - (sum(payVal))) > 0 ...>
SELECT *, SUM(p.payVal) AS TotalPayed
FROM orders o
LEFT JOIN payments p ON o.orderID = p.orderID
GROUP BY o.orderID
HAVING SUM(p.payVal) < o.orderValue
This should provide you with the necessary fields, although I would advise you to select specific fields with this query.
The LEFT JOIN makes sure you get every order, even if there are no payments made yet.
SQL Fiddle
Looks like we came to the same solution,
http://sqlfiddle.com/#!2/9a657/18
SELECT * FROM `orders`
LEFT JOIN `payments` AS p ON `orders`.`orderID` = p.`orderID`
GROUP BY `orders`.`orderID`
HAVING SUM(p.`payVal`) <= 0
I've got a large mysql query with 5 joins which may not seem efficient but I'm struggling to find a different solution which would work.
The views table is the main table here, because both clicks and conversions table rely on it via the token column(which is indexed and set as a foreign key in all tables).
The query:
SELECT
var.id,
var.disabled,
var.name,
var.updated,
var.cid,
var.outdated,
IF(var.type <> 0,'DL','LP') AS `type`,
COUNT(DISTINCT v.id) AS `views`,
COUNT(DISTINCT c.id) AS `clicks`,
COUNT(DISTINCT co.id) AS `conversions`,
SUM(tc.cost) AS `cost`,
SUM(cp.value) AS `revenue`
FROM variants AS var
LEFT JOIN views AS v ON v.vid = var.id
LEFT JOIN traffic_cost AS tc ON tc.id = v.source
LEFT JOIN clicks AS c ON c.token = v.token
LEFT JOIN conversions AS co ON co.token = v.token
LEFT JOIN c_profiles AS cp ON cp.id = co.profile
WHERE var.cid = 28
GROUP BY var.id
The results I'm getting are:
The problem is the revenue and cost results are too hight, because for views,clicks and impressions only the distinct rows are counted, but for revenue and cost for some reason(I would really appreciate an explanation here) all rows in all tables are taken into the result set.
I know this is a large query, but both clicks and conversions tables rely on the views table which is used for filtering the results e.g. views.country = 'uk'. I've tried doing 3 queries and merging them, but that didn't work(it gave me wrong results).
One more thing that I find weird is that if I remove the joins with clicks, conversions, c_profiles the costs column shows correct results.
Any help would be appreciated.
In the end I had to use 3 different queries and do a merge on them. Seemed like an overhead, but worked for me.