ACCESS SQL, Monthly DISTINCT aggregate SUM - ms-access

I would like to calculate monthly aggregate Sums with Distinct values. I have an INTERNET_SALES_RECEIPT table that has a record for each item sold with a foreign key to the INTERNET_SHIPPING_CHARGES table.
The items that are shipped in the same box have the same foreign key from the INTERNET_SHIPPING_CHARGES table.
The following code runs but the query cannot find the values for months.month_start and months.month_end causing the query to issue a prompt and get hung up.
SELECT Format(DatePart("m", months.month_start), "00") & "/" & Year(months.month_start) AS [Month/Year],
(SELECT Round(Nz(Sum(internet_shipping_charges.shipping_collected), 0), 2)
FROM
(SELECT DISTINCT internet_shipping_charges.shipping_collected
FROM internet_shipping_charges
INNER JOIN INTERNET_SALES_RECEIPT ON INTERNET_SALES_RECEIPT.INTERNET_SHIPPING_ID = INTERNET_SHIPPING_CHARGES.INTERNET_SHIPPING_ID
WHERE internet_sales_receipt.SALE_DATE BETWEEN months.month_start AND months.month_end )
) AS [Total Shipping Collected],
(SELECT Round(Nz(Sum(internet_shipping_charges.shipping_actual_cost), 0), 2)
FROM
(SELECT DISTINCT internet_shipping_charges.shipping_actual_cost
FROM internet_shipping_charges
INNER JOIN INTERNET_SALES_RECEIPT ON INTERNET_SALES_RECEIPT.INTERNET_SHIPPING_ID = INTERNET_SHIPPING_CHARGES.INTERNET_SHIPPING_ID
WHERE internet_sales_receipt.SALE_DATE BETWEEN months.month_start AND months.month_end )
) AS [Total Shipping Actual Cost],
(SELECT Round(Nz(Sum(internet_shipping_charges.shipping_collected), 0) - Nz(Sum(internet_shipping_charges.shipping_actual_cost), 0), 2)
FROM
(SELECT DISTINCT internet_shipping_charges.shipping_collected, internet_shipping_charges.shipping_actual_cost
FROM internet_shipping_charges
INNER JOIN INTERNET_SALES_RECEIPT ON INTERNET_SALES_RECEIPT.INTERNET_SHIPPING_ID = INTERNET_SHIPPING_CHARGES.INTERNET_SHIPPING_ID
WHERE internet_sales_receipt.[SALE_DATE] BETWEEN months.month_start AND months.month_end)
) AS [Shipping Gain/Loss]
FROM
(SELECT DateSerial(Year(sale_date), Month(sale_date), 1) AS month_start,
DateAdd("d", -1, DateSerial(Year(sale_date), Month(sale_date) + 1, 1)) AS month_end
FROM internet_sales_receipt
WHERE sale_date BETWEEN DateAdd("yyyy", [Enter last two digits of year], #1/1/2000#) AND DateAdd("yyyy", [Enter last two digits of year], #12/31/2000#)
GROUP BY Year(sale_date), Month(sale_date)
) AS months;
I tried adding various forms of the DatePart() function to the subqueries but always got the same error of missing values for months.month_start and months.month_end.

SELECT Format(DatePart("m", months.month_start), "00") & "/" & Year(months.month_start) AS [Month/Year],
(SELECT Round(Nz(sum(internet_shipping_charges.shipping_collected), 0), 2)
FROM
(SELECT DISTINCT internet_shipping_charges.shipping_collected, internet_sales_receipt.SALE_DATE
FROM internet_shipping_charges
INNER JOIN INTERNET_SALES_RECEIPT ON INTERNET_SALES_RECEIPT.INTERNET_SHIPPING_ID = INTERNET_SHIPPING_CHARGES.INTERNET_SHIPPING_ID)
WHERE internet_sales_receipt.SALE_DATE BETWEEN months.month_start AND months.month_end
) AS [Total Shipping Collected],
(SELECT Round(Nz(sum(internet_shipping_charges.shipping_actual_cost), 0), 2)
FROM
(SELECT DISTINCT internet_shipping_charges.shipping_actual_cost, internet_sales_receipt.SALE_DATE
FROM internet_shipping_charges
INNER JOIN INTERNET_SALES_RECEIPT ON INTERNET_SALES_RECEIPT.INTERNET_SHIPPING_ID = INTERNET_SHIPPING_CHARGES.INTERNET_SHIPPING_ID)
WHERE internet_sales_receipt.SALE_DATE BETWEEN months.month_start AND months.month_end
) AS [Total Shipping Actual Cost],
(SELECT Round(Nz(sum(internet_shipping_charges.shipping_collected), 0) - Nz(sum(internet_shipping_charges.shipping_actual_cost), 0), 2)
FROM
(SELECT DISTINCT internet_shipping_charges.shipping_collected, internet_shipping_charges.shipping_actual_cost, internet_sales_receipt.SALE_DATE
FROM internet_shipping_charges
INNER JOIN INTERNET_SALES_RECEIPT ON INTERNET_SALES_RECEIPT.INTERNET_SHIPPING_ID = INTERNET_SHIPPING_CHARGES.INTERNET_SHIPPING_ID)
WHERE internet_sales_receipt.[SALE_DATE] BETWEEN months.month_start AND months.month_end
) AS [Shipping Gain/Loss]
FROM
(SELECT DateSerial(Year(sale_date), Month(sale_date), 1) AS month_start,
DateAdd("d", -1, DateSerial(Year(sale_date), Month(sale_date) + 1, 1)) AS month_end
FROM internet_sales_receipt
WHERE sale_date BETWEEN DateAdd("yyyy", [Enter last two digits of year], #1/1/2000#) AND DateAdd("yyyy", [Enter last two digits of year], #12/31/2000#)
GROUP BY Year(sale_date), Month(sale_date)
) AS months;

Related

Comparing and Matching keybinds while comparing 2 tables and returning count

Currently I have 2 tables, a listing table and a logs table. With the following query I'm trying to get the listings of a product on a particular day, and it returns the right output.
with X as (
select l.*,
(select status_from from logs where logs.refno = l.refno and logs.logtime >= '2021-10-01' order by logs.logtime limit 1) logstat
from listings l
where l.added_date < '2021-10-01')
select X.*, ifnull(X.logstat,X.status) stat20211001 from X;
I've tried the following in this dbfiddle(https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=b0e433b59b5c4a4a0be3f0bc25d20124) with the following table for listings:
(3, 'Publish','2021-05-02','2021-10-02','LP01'), (4, 'Action','2021-05-01','2021-05-01','LP02'),
(5, 'Sold','2020-10-01','2020-10-01','LP03'), (6, 'Let','2021-05-01','2021-10-06','LP06'),
(10, 'Draft','2021-10-06','2021-10-06','LP05'), (11, 'Draft','2021-01-01','2021-01-01','LP04');
But now in my actual database, the statuses are represented by a particular keybind. For example, ('D' => 'Draft', 'A' => 'Action', 'Y' => 'Publish', 'S' => 'Sold', 'N' => 'Let'):
So basically that makes my actual listings table with the following data:
(3, 'Y','2021-05-02','2021-10-02','LP01'), (4, 'A','2021-05-01','2021-05-01','LP02'),
(5, 'S','2020-10-01','2020-10-01','LP03'), (6, 'N','2021-05-01','2021-10-06','LP06'),
(10, 'D','2021-10-06','2021-10-06','LP05'), (11, 'D','2021-01-01','2021-01-01','LP04');
Now I want a way to have the same output of my query above, but show it with the new data and instead of showing The output it is showing right now in words, it should group similar statuses and return a count for that data. For example:
status
Count
Publish(Y)
0
Action(A)
3
Let(N)
0
Sold(S)
1
Draft(D)
1
Basically I want something like this to be added to the statement I think:
SELECT case status
when 'D' THEN 'Draft'
when 'A' THEN 'Action'
when 'Y' THEN 'Publish'
when 'S' THEN 'Sold'
when 'N' THEN 'Let'
END status_l ,COUNT(*) c from listings
group by status
I suggest you create a status table in your database. Use this table, outer join your query and count:
with X as (
select
l.*,
(select status_from
from logs
where logs.refno = l.refno
and logs.logtime >= '2021-10-01'
order by logs.logtime
limit 1) logstat
from listings l
where l.added_date < '2021-10-01'
)
, Y as (select X.*, ifnull(X.logstat, X.status) stat20211001 from X)
SELECT
status.text,
COUNT(Y.id) AS c
from status
left join Y on Y.stat20211001 = status.code
group by status.code;
Demo: https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=673125506bb29b9d10719010aa2e00ae
Looks like you need in something like
with X as (
select l.*,
(select status_from from logs where logs.refno = l.refno and logs.logtime >= '2021-10-01' order by logs.logtime limit 1) logstat
from listings l
where l.added_date < '2021-10-01'),
statustable AS (SELECT 'Draft' status UNION ALL
SELECT 'Action' UNION ALL
SELECT 'Publish' UNION ALL
SELECT 'Sold' UNION ALL
SELECT 'Let')
select X.*,
COALESCE(X.logstat, statustable.status) stat20211001
from X
LEFT JOIN statustable ON X.status = LEFT(statustable.status, 1);
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=6b65365be8c3403b329a1b4b56212a03
Hmm no I tried this, but it does not give the right output. The output I want is something like the table I have provided above – JJM50
My query prepares everything for final grouping - I thought that was enough...
with X as (
select l.*,
(select status_from from logs where logs.refno = l.refno and logs.logtime >= '2021-10-01' order by logs.logtime limit 1) logstat
from listings l
where l.added_date < '2021-10-01'),
statustable AS (SELECT 'Draft' status UNION ALL
SELECT 'Action' UNION ALL
SELECT 'Publish' UNION ALL
SELECT 'Sold' UNION ALL
SELECT 'Let'),
preparedata AS ( select COALESCE(X.logstat, statustable.status) stat20211001
from X
LEFT JOIN statustable ON X.status = LEFT(statustable.status, 1) )
SELECT t1.status, COUNT(t2.stat20211001)
FROM statustable t1
LEFT JOIN preparedata t2 ON t1.status = t2.stat20211001
GROUP BY t1.status
https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=0edec9fbd3f07892e70f7a549117af8d

How to sum subqueries in MySQL

I have the following MySQL statement that works perfectly. However I now need a total as designated in bold square brackets/parenthesis below.
SELECT f.fid, r.tid, r.tbd, r.tbc, r.tc, r.tname, r.category,
SUM(`time`) AS `totaltime`,
SUM(`points`) AS `points`,
(SELECT IFNULL(SUM(points),0) FROM Primes WHERE zid = r.zid AND wid = r.wid AND s_id = 38) AS `cl`,
(SELECT IFNULL(SUM(points),0) FROM Primes WHERE zid = r.zid AND wid = r.wid AND s_id = 34) AS `sp`,
**[sum points + climb + sprint] AS pointstotal**
FROM teams f
JOIN results r
ON f.wid = r.wid
WHERE r.rank <= 3 AND r.id = '254293' AND r.category = 'C'
AND r.fin = '1'
GROUP BY f.fid
ORDER BY pointstotal DESC
I have tried many different permutations etc and multiple references in other questions but I just cant get it to work.
The simplest way is to move your query into a subquery, and then add those columns.
SELECT fid, tid, tbd, tbc, tc, tname, category, totaltime,
points, cl, sp, points + cl + sp AS pointstotal
FROM (
SELECT f.fid, r.tid, r.tbd, r.tbc, r.tc, r.tname, r.category,
SUM(`time`) AS `totaltime`,
SUM(`points`) AS `points`,
(SELECT SUM(points) FROM Primes WHERE zid = r.zid AND wid = r.wid AND s_id = 38) AS `cl`,
(SELECT SUM(points) FROM Primes WHERE zid = r.zid AND wid = r.wid AND s_id = 34) AS `sp`
FROM teams f
JOIN results r
ON f.wid = r.wid
WHERE r.rank <= 3 AND r.id = '254293' AND r.category = 'C'
AND r.fin = '1'
GROUP BY f.fid
) AS x
ORDER BY pointstotal DESC
But I generally dislike correlated subqueries, I prefer joins, and then you don't need another level
SELECT SELECT f.fid, r.tid, r.tbd, r.tbc, r.tc, r.tname, r.category,
SUM(time) AS totaltime, SUM(points) AS points,
cl, sp, SUM(POINTS) + cl + sp AS totalpoints
FROM teams AS f
JOIN results AS r ON f.wid = r.wid
JOIN (
SELECT zid, wid, SUM(IF(s_id = 38, points, 0)) AS cl, SUM(IF(s_id = 34, points, 0)) AS sp
FROM Primes
GROUP BY zid, wid
) AS p ON p.zid = r.zid AND p.wid = r.wid
WHERE r.rank <= 3 AND r.id = '24293' AND r.category = 'C' AND r.fin = '1'
GROUP BY f.fid
ORDER BY pointstotal DESC

ACCESS Sub-queries and aggregate calculations

I have a SALES RECEIPT table and a RETURNS table. The information in the two tables are independent of each other except that each table has the Rep_ID attribute from the SALES_REP table.
In the first sub-query, I calculate the sum of the “Total Sales” and the “Gross Commission” from the SALES RECEIPT table for each sales person on a monthly basis.
In the second sub-query, I calculate the sum of the “Return Sales” and the “Lost Commission” from the RETURNS table for each sales person on a monthly basis.
In the main query, I want to display for each sales person on a monthly basis the “Total Sales”,
“Gross Commission”, “Return Sales”, “Lost Commission” and “Net Commission”. The “Net Commission” is the “Gross Commission” minus the “Lost Commission”.
With the code I have, I get the error message:
"The Microsoft Access database engine cannot find the input table or query ‘totSales’. Make sure it exists and that its name is spelled correctly.”
Select
totSales.Year-Month as [Month/Year],
SALES_REP.rep_name as [Sales Person],
SUM(totSales.[Total Sales]) as [Total Sales],
SUM(totSales.[Gross Commission]) as [Gross Commission],
SUM(totReturns.[Return Sales],0) as [Sales Returns],
SUM(totReturns.[Lost Commission],0) as [Lost Commission],
Round([Gross Commission] - [Lost Commission],2) AS [Net Commission],
(SELECT
Format(SALES_RECEIPT.sale_date,'yyyy-mm') AS [Year-Month],
SALES_RECEIPT.rep_id,
( SALES_RECEIPT.selling_price * SALES_RECEIPT.quantity) AS [Total Sales],
((Nz(SALES_RECEIPT.selling_price, 0) * Nz( SALES_RECEIPT.quantity, 0)) * (Nz(SALES_RECEIPT.commission_percent, 100) * 0.001)) AS [Gross Commission]
FROM
SALES_RECEIPT
WHERE
SALES_RECEIPT.sale_date Between #1/1/2000# And #12/31/2050#) AS totSales,
(SELECT
RETURNS.rep_id,
(Nz(RETURNS.selling_price * RETURNS.quantity)) AS [Sales Returns],
((Nz(RETURNS.selling_price, 0) * Nz(RETURNS.quantity, 0)) * (Nz(RETURNS.commission_percent, 100) * 0.001)) AS [Lost Commission]
FROM
RETURNS
WHERE
RETURNS.return_date Between #1/1/2000# And #12/31/2050#) As totReturns
From (totSales
LEFT JOIN totReturns on totReturns.rep_id = totSales.rep_id)
INNER JOIN SALES_REP ON totSales.REP_ID = SALES_REP.rep_id
Group By totSales.Year-Month, totSales.rep_name;
The query below returns monthly sales commission data but only for one sales person. I want the above query to return the exact same results as the query below but for all sales persons not just one sales person.
SELECT Format(DatePart("m",months.month_start),"00") & "/" & Year(months.month_start) AS [Month/Year],
(SELECT SALES_REP.rep_name FROM SALES_REP WHERE SALES_REP.rep_id = 1) AS [Sales Person],
(select Round(Nz(Sum(sales_receipt.SELLING_PRICE * sales_receipt.quantity),0) ,2)
FROM SALES_RECEIPT INNER JOIN SALES_REP ON SALES_REP.REP_ID = SALES_RECEIPT.REP_ID
WHERE SALES_RECEIPT.[SALE_DATE] between months.month_start and months.month_end and SALES_REP.rep_id = 1) AS [Total Sales],
(SELECT Round((Sum(((Nz(SALES_RECEIPT.SELLING_PRICE,0)*Nz(sales_receipt.quantity,0))*(Nz(sales_receipt.commission_percent,100)*0.001)))),2)
FROM SALES_RECEIPT INNER JOIN SALES_REP ON SALES_REP.REP_ID = SALES_RECEIPT.REP_ID
WHERE SALES_RECEIPT.[SALE_DATE] between months.month_start and months.month_end and SALES_REP.rep_id = 1) AS [Gross Commission],
(SELECT Round(Nz(Sum(returns.selling_price * returns.quantity), 0),2)
FROM (returns inner JOIN inventory ON INVENTORY.INVENTORY_ID = returns.INVENTORY_ID)
LEFT JOIN SALES_REP ON SALES_REP.REP_ID = returns.REP_ID
WHERE returns.return_date between months.month_start and months.month_end AND SALES_REP.rep_id = 1) AS [Sales Returns],
(SELECT Round(Nz((Sum(((Nz(returns.SELLING_PRICE,0)*Nz(returns.quantity,0))*(Nz(returns.commission_percent,100)*0.001)))),0),2)
FROM (returns inner JOIN inventory ON INVENTORY.INVENTORY_ID = returns.INVENTORY_ID)
LEFT JOIN SALES_REP ON SALES_REP.REP_ID = returns.REP_ID
WHERE returns.return_date between months.month_start and months.month_end AND SALES_REP.rep_id = 1) AS [Lost Commission],
(SELECT Round((Sum(((Nz(SALES_RECEIPT.SELLING_PRICE,0)*Nz(sales_receipt.quantity,0))*(Nz(sales_receipt.commission_percent,100)*0.001)))),2)
FROM SALES_RECEIPT INNER JOIN SALES_REP ON SALES_REP.REP_ID = SALES_RECEIPT.REP_ID WHERE SALES_RECEIPT.[SALE_DATE] between months.month_start and months.month_end and SALES_REP.rep_id = 1) - (SELECT Round(Nz((Sum(((Nz(returns.SELLING_PRICE,0)*Nz(returns.quantity,0))*(Nz(returns.commission_percent,100)*0.001)))),0),2)
FROM(returns inner JOIN inventory ON INVENTORY.INVENTORY_ID = returns.INVENTORY_ID)
LEFT JOIN SALES_REP ON SALES_REP.REP_ID = returns.REP_ID
WHERE returns.return_date between months.month_start and months.month_end AND SALES_REP.rep_id = 1) AS [Net Commission]
FROM
(SELECT DateSerial(Year(sale_date), Month(sale_date), 1) AS month_start,
DateAdd("d", -1, DateSerial(Year(sale_date), Month(sale_date) + 1, 1)) AS month_end
FROM SALES_RECEIPT
WHERE sale_date between #1/1/2000# And #12/31/2100#
GROUP BY Year(sale_date), Month(sale_date)) AS months;
Move the two subqueries so that they are in the FROM...JOIN section of the query. As #Leviathan noted, the query is currently treating them as if they were fields (which they aren't, of course).
Also: be sure that you include all of the fields by which you are grouping in the GROUP BY clause (and do not alias them--you'll get an error).
Here's a stab at the first query. Access is screwy with how it likes parentheses when you're doing multiple joins, so apologies if it doesn't work the first time:
Select
totSales.Year-Month as [Month/Year],
SALES_REP.rep_name as [Sales Person],
SUM(totSales.[Total Sales]) as [Total Sales],
SUM(totSales.[Gross Commission]) as [Gross Commission],
SUM(totReturns.[Return Sales],0) as [Sales Returns],
SUM(totReturns.[Lost Commission],0) as [Lost Commission],
Round(TotCommissions - TotLostCommissions,2) AS [Net Commission]
FROM
SALES_REP
INNER JOIN
(
(SELECT
Format(SALES_RECEIPT.sale_date,'yyyy-mm') AS [Year-Month],
SALES_RECEIPT.rep_id,
( SALES_RECEIPT.selling_price * SALES_RECEIPT.quantity) AS [Total Sales],
((Nz(SALES_RECEIPT.selling_price, 0) * Nz( SALES_RECEIPT.quantity, 0)) * (Nz(SALES_RECEIPT.commission_percent, 100) * 0.001)) AS [Gross Commission]
FROM
SALES_RECEIPT
WHERE
SALES_RECEIPT.sale_date Between #1/1/2000# And #12/31/2050#) AS totSales
LEFT JOIN
(SELECT
RETURNS.rep_id,
(Nz(RETURNS.selling_price * RETURNS.quantity)) AS [Returns Sales],
((Nz(RETURNS.selling_price, 0) * Nz(RETURNS.quantity, 0)) * (Nz(RETURNS.commission_percent, 100) * 0.001)) AS [Lost Commission]
FROM
RETURNS
WHERE
RETURNS.return_date Between #1/1/2000# And #12/31/2050#) As totReturns
on totReturns.rep_id = totSales.rep_id
)
ON totSales.REP_ID = SALES_REP.rep_id
Group By
totSales.Year-Month
,SALES_REP.rep_name
,Round(TotCommissions - TotLostCommissions,2)
;
Also: as a style thing: it's generally preferred to put the commas separating multiple fields on the line with the field that follows them, e.g.:
SELECT
SomeField
,SomeOtherField
not:
SELECT
SomeField,
SomeOtherField
Some folks get really bent out of shape about it, so probably a good idea to try and get in the habit of leading with the comma to spare yourself unnecessary criticism.

Any way to reference MySQL "AS" values within the query?

in the following query, I sum up all the Sale Items of all the Sales in the given range. Included in this summary is "sumOfCost" and "sumOfPrice", I'd like "sumOfProfit" too. The problem is, as they're only "AS" variables, I'm not sure how to reference them, and my attempt of "... Blah AS blah, sumOfPrice - sumOfCost = sumOfProfit ..." sadly didn't work!
Here is my query:
SELECT Sales.SaleID,
Sales.StaffID,
Sales.CustomerID,
Sales.Timestamp,
Sales.Refunded,
Sales.PaymentType,
Staff.Forename AS staffForename,
Staff.Surname AS staffSurname,
(
SELECT GROUP_CONCAT(Quantity, ' x ', Name)
FROM SaleItems
WHERE SaleItems.SaleID = Sales.SaleID
) AS itemList,
(
SELECT sum(Cost*Quantity)
FROM SaleItems
WHERE SaleItems.SaleID = Sales.SaleID
) AS sumOfCost,
(
SELECT sum(Price*Quantity)
FROM SaleItems
WHERE SaleItems.SaleID = Sales.SaleID
) AS sumOfPrice
FROM Sales
INNER JOIN Staff
ON Sales.StaffID = Staff.StaffID
WHERE Sales.Deleted = '0'
ORDER BY Timestamp DESC
LIMIT 0, 15
Apologies for the length of the query, I've struggled before to optimise it better but right now I'm only looking to solve this problem.
Thanks in advance :)
One alternative to solve this problem is by wrapping the whole query with a subquery,
SELECT *,
sumOfCost - sumOfPrice AS sumOfProfit
FROM
(
SELECT Sales.SaleID,
Sales.StaffID,
Sales.CustomerID,
Sales.Timestamp,
Sales.Refunded,
Sales.PaymentType,
Staff.Forename AS staffForename,
Staff.Surname AS staffSurname,
(
SELECT GROUP_CONCAT(Quantity, ' x ', Name)
FROM SaleItems
WHERE SaleItems.SaleID = Sales.SaleID
) AS itemList,
(
SELECT sum(Cost*Quantity)
FROM SaleItems
WHERE SaleItems.SaleID = Sales.SaleID
) AS sumOfCost,
(
SELECT sum(Price*Quantity)
FROM SaleItems
WHERE SaleItems.SaleID = Sales.SaleID
) AS sumOfPrice
FROM Sales
INNER JOIN Staff
ON Sales.StaffID = Staff.StaffID
WHERE Sales.Deleted = '0'
ORDER BY Timestamp DESC
LIMIT 0, 15
) s
By the way, they are called ALIAS.
The reason why ALIAS can't be used for calculation on the same level where they were defined is because the server executes the FROM clause before the SELECT clause. The ALIAS are on the SELECT clause, here's the full SQL Order of Operation:
FROM clause
WHERE clause
GROUP BY clause
HAVING clause
SELECT clause
ORDER BY clause
For better performance issue, I'll rather using JOIN than subqueries.
UPDATE 1
SELECT Sales.SaleID,
Sales.StaffID,
Sales.CustomerID,
Sales.Timestamp,
Sales.Refunded,
Sales.PaymentType,
Staff.Forename AS staffForename,
Staff.Surname AS staffSurname,
COALESCE(a.itemList, '') itemList,
COALESCE(b.sumOfCost, 0) sumOfCost,
COALESCE(c.sumOfPrice, 0) sumOfPrice,
COALESCE(b.sumOfCost, 0) - COALESCE(c.sumOfPrice, 0) AS sumOfProfit
FROM Sales
INNER JOIN Staff
ON Sales.StaffID = Staff.StaffID
LEFT JOIN
(
SELECT SaleID, GROUP_CONCAT(Quantity, ' x ', Name) itemList
FROM SaleItems
GROUP BY SaleID
) a ON a.SaleID = Sales.SaleID
LEFT JOIN
(
SELECT SaleID, sum(Cost*Quantity) sumOfCost
FROM SaleItems
GROUP BY SaleID
) b ON b.SaleID = Sales.SaleID
LEFT JOIN
(
SELECT SaleID, sum(Price*Quantity) sumOfPrice
FROM SaleItems
GROUP BY SaleID
) c ON c.SaleID = Sales.SaleID
WHERE Sales.Deleted = '0'
ORDER BY Timestamp DESC
LIMIT 0, 15
UPDATE 2
SELECT Sales.SaleID,
Sales.StaffID,
Sales.CustomerID,
Sales.TIMESTAMP,
Sales.Refunded,
Sales.PaymentType,
Staff.Forename AS staffForename,
Staff.Surname AS staffSurname,
COALESCE(a.itemList, '') itemList,
COALESCE(a.sumOfCost, 0) sumOfCost,
COALESCE(a.sumOfPrice, 0) sumOfPrice,
COALESCE(a.sumOfCost, 0) - COALESCE(a.sumOfPrice, 0) AS sumOfProfit
FROM Sales
INNER JOIN Staff
ON Sales.StaffID = Staff.StaffID
LEFT JOIN
(
SELECT SaleID,
GROUP_CONCAT(Quantity, ' x ', Name) itemList,
SUM(Cost*Quantity) sumOfCost,
SUM(Price*Quantity) sumOfPrice
FROM SaleItems
GROUP BY SaleID
) a ON a.SaleID = Sales.SaleID
WHERE Sales.Deleted = '0'
ORDER BY TIMESTAMP DESC
LIMIT 0, 15

Help calculating average per day

The daily_average column is always returning zero. The default timestamp values are for the past week. Any thoughts on what I'm doing wrong here in getting the average order value per day?
SELECT
SUM(price+shipping_price) AS total_sales,
COUNT(id) AS total_orders,
AVG(price+shipping_price) AS order_total_average,
(SELECT
SUM(quantity)
FROM `order_product`
INNER JOIN `order` ON (
`order`.id = order_product.order_id AND
`order`.created >= '.$startTimestamp.' AND
`order`.created <= '.$endTimestamp.' AND
`order`.type_id = '.$type->getId().' AND
`order`.fraud = 0
)
) as total_units,
SUM(price+shipping_price)/DATEDIFF('.$endTimestamp.', '.$startTimestamp.') as daily_average
FROM `order`
WHERE created >= '.$startTimestamp.' AND
created <= '.$endTimestamp.' AND
fraud = 0 AND
type_id = '.$type->getId().'
You're using aggregate functions (SUM, COUNT, AVG) without an aggregate command (group by). I think your SQL is more complicated than it needs to be (no need for the inner select).
Here's a SQL command that should work (hard to test without test data ;))
SELECT
COUNT(id) total_orders,
SUM(finalprice) total_sales,
AVG(finalprice) order_average,
SUM(units) total_units,
SUM(finalprice)/DATEDIFF('.$endTimestamp.', '.$startTimestamp.') daily_average
FROM (
SELECT
o.id id,
o.price+o.shipping_price finalprice,
SUM(p.quantity) units
FROM order o INNER JOIN order_product p ON p.order_id=o.id
WHERE o.created>='.$startTimestamp.'
AND o.created<='.$endTimestamp.'
AND o.fraud=0
AND o.type_id='.$type->getId().'
GROUP BY p.order_id
) t;
Does casting one of the elements in the division work for you?
SELECT
SUM(price+shipping_price) AS total_sales,
COUNT(id) AS total_orders,
AVG(price+shipping_price) AS order_total_average,
(SELECT
SUM(quantity)
FROM `order_product`
INNER JOIN `order` ON (
`order`.id = order_product.order_id AND
`order`.created >= '.$startTimestamp.' AND
`order`.created <= '.$endTimestamp.' AND
`order`.type_id = '.$type->getId().' AND
`order`.fraud = 0
)
) as total_units,
CAST(SUM(price+shipping_price) AS float)/DATEDIFF('.$endTimestamp.', '.$startTimestamp.') as daily_average
FROM `order`
WHERE created >= '.$startTimestamp.' AND
created <= '.$endTimestamp.' AND
fraud = 0 AND
type_id = '.$type->getId().'