I've had a look at this question (Please help merging 4 MySQL queries to One) hoping it would help, but it doesn't. I can't make sense of it because my brain is fried.
I'm trying to get my head around merging four SELECT statements, all of which work individually, into one.
The fields are;
QUANTITY: INT;
ORDERDATE: DATE; // Not datetime - I don't need time.
MySQL Version 5.6.17
The data I'm retrieving is;
1) Number of products ordered this financial year;
SELECT SUM(QUANTITY) AS YTD
FROM ORDERDETAILS
WHERE ORDERDATE BETWEEN "2016-07-01" AND "2017-02-16"
Note that in Australia the Financial Year is 1st of July through to 30th of June.
2) Number of products ordered this month;
SELECT SUM(QUANTITY) AS MONTHY
FROM ORDERDETAILS
WHERE ORDERDATE BETWEEN "2017-02-01" AND "2017-02-16"
3) Number of products ordered today;
SELECT SUM(QUANTITY) AS TODAYS
FROM ORDERDETAILS
WHERE ORDERDATE = "2017-02-16"
4) Average number of products ordered per order;
SELECT AVG(QUANTITY) AS BOOGER
FROM ORDERDETAILS
WHERE ORDERDATE BETWEEN "2016-07-01" AND "2017-02-16"
I want to avoid sending four separate statements to the server. Perhaps it can't be done, but if I could achieve the same results in a single statement I'd be happy.
I've looked at joins, embedding select within selects but can't get my head around it.
Once I get the data all I do is update a couple of labels on a form (Delphi).
Any tips that a nearly 55 year old brain can handle would be appreciated.
You can do this using case when condition:
select
sum(case when ORDERDATE BETWEEN '2016-07-01' AND '2017-02-16' then QUANTITY end ) as YTD,
sum(case when ORDERDATE BETWEEN '2017-02-01' AND '2017-02-16' then QUANTITY end ) as MONTHY,
sum(case when ORDERDATE = '2017-02-16' then QUANTITY end ) as TODAYS,
AVG(case when ORDERDATE BETWEEN '2016-07-01' AND '2017-02-16' then QUANTITY end ) as BOOGER
FROM ORDERDETAILS
You simply have to use a different alias on the different calls to the table and put it all in one SELECT statement as follows:
SELECT SUM(od1.QUANTITY) AS YTD,
SUM(od2.QUANTITY) AS MONTHLY,
SUM(od3.QUANTITY) AS TODAYS,
AVG(od4.QUANTITY) AS BOOGER
FROM ORDERDETAILS od1,
ORDERDETAILS od2,
ORDERDETAILS od3,
ORDERDETAILS od4
WHERE od1.ORDERDATE BETWEEN CAST('2016-07-01' AS DATE) AND CAST('2017-02-16' AS DATE)
AND od2.ORDERDATE BETWEEN CAST('2017-02-01' AS DATE) AND CAST('2017-02-16' AS DATE)
AND od3.ORDERDATE = CAST('2017-02-16' AS DATE)
AND od4.ORDERDATE BETWEEN CAST('2016-07-01' AS DATE) AND CAST('2017-02-16' AS DATE)
Use SUM(IF()) pattern and move condition inside the IF.
SELECT
SUM(IF(ORDERDATE BETWEEN "2016-07-01" AND "2017-02-16", QUANTITY, 0)) AS YTD,
SUM(IF(ORDERDATE BETWEEN "2017-02-01" AND "2017-02-16", QUANTITY, 0)) AS MONTHY,
SUM(IF(ORDERDATE = "2017-02-16", QUANTITY, 0)) AS TODAYS,
SUM(IF(ORDERDATE BETWEEN "2016-07-01" AND "2017-02-16", QUANTITY, 0)) / COUNT(IF(ORDERDATE BETWEEN "2016-07-01" AND "2017-02-16", 1, NULL)) AS BOOGER
FROM ORDERDETAILS
WHERE ORDERDATE BETWEEN "2016-07-01" AND "2017-02-16";
Consider using CURDATE() for today's date.
Also a WHERE clause can be added so that all rows of table are not scanned e.g. WHERE ORDERDATE BETWEEN "2016-07-01" AND "2017-02-16" after FROM ORDERDETAILS
Related
In my table (named checkout) in the database I have the
price (price of the item)
discount (what percentage of discount it had, eg 50 (for 50%))
howmany (which is the quantity of the product)
date (which is the current date)
I want my query to fetch the sum of the prices that had no discount on it and the sum of the prices that had discount on it for the year that we have and group it based on the month.
In the first SELECT I get the price multiplied by the quantity and it's without discount (works perfectly fine) but when I added the sub Query, the Query does not work. Any suggestions?
The (price*(1-(discount/100) in the Sub Query, first gets the discount for example 30/100=0.3 then it substracts it from the 1 (1-0.3=0.7 ) then I multiplied it with the price (price*0.7) and it returns the price with the discount
$sqlQuery = "SELECT sum(price*howmany) as price,
(SELECT sum((price*(1-(discount/100))*howmany) as price
FROM checkout
WHERE '$year'=YEAR(date) AND discount IS NOT NULL
GROUP BY Month(date)
ORDER BY Month(date)) as discountPrice
FROM checkout
WHERE '$year'=YEAR(date) AND discount IS NULL
GROUP BY Month(date)
ORDER BY Month(date) ";
you don't need a subquery. You can put the discount condition inside the SUM() calls.
SELECT
MONTH(date) AS month,
SUM(IF(discount IS NULL, price, 0) * howmany) AS price,
SUM(IF(discount IS NOT NULL, price*(1-(discount/100))*howmany, 0) AS discountPrice
FROM checkout
WHERE YEAR(date) = $year
GROUP BY month
ORDER BY month
See need to return two sets of data with two different where clauses
Hello I am currently training in SQL on MySQL, and I'm stuck with a problem where I want the number of products sold by category, and by month, with comparison and rate of change compared to the same month of the previous year.
Here is what I have done for now:
SELECT
productLine,
EXTRACT( year from orderDate) orderYear,
EXTRACT( month from orderDate) orderMonth,
SUM(CASE WHEN MONTH(orderDate) IS NOT NULL THEN quantityOrdered ELSE 0 END) orderQuantity,
LAG(SUM(CASE WHEN MONTH(orderDate) IS NOT NULL THEN quantityOrdered ELSE 0 END),12) OVER (ORDER BY productLine, YEAR(orderDate), MONTH(orderDate)) orderQuantity_prevYear,
CONCAT(ROUND((quantityOrdered - LAG(quantityOrdered,12) OVER ( ORDER BY productLine, YEAR(orderDate), MONTH(orderDate)))*100/LAG(quantityOrdered,12)OVER ( ORDER BY productLine, YEAR(orderDate), MONTH(orderDate)),0),'%') AS month_to_month_difference
FROM
orderDetails
INNER JOIN
orders USING (orderNumber)
INNER JOIN
products USING (productCode)
WHERE
YEAR(orderDate) > (YEAR(orderDate) - 1)
GROUP BY
productLine ,
YEAR(orderDate),
MONTH(orderDate)
ORDER BY
productLine,
YEAR(orderDate),
MONTH(orderDate)
;
But the problem is that when I don't have a quantity sold for a certain month, everything shifts in my lines and the values are no longer the right ones. See Motorcycles 2019-9 to 2019-11 skipping 2019-10.
How can I display the months when there was no sales on a product category? I tried something with the CASE WHEN but it appear that it does not work.
Thank you in advance, and hope this is detailed enough.
I am trying to export sales report from table 'sales'
It has field names pname, price, sold_to, pquantity, pamount, date
Here I don't wish to display the same company I sold_to over and over if the company purchased same product on 2021-02-13 so I tried to group by the query but then it isn't showing total sum of pquantity and pamount in results even though it groups same company.
could someone help me out with fixing the query?
Here is my MYSQL query:
SELECT * FROM sales
WHERE DATE_FORMAT(date, '%Y-%m-%d') BETWEEN '$from' AND '$to'
GROUP BY pname, sold_to, pquantity, pamount, date
ORDER BY sale_id DESC
I am definitely doing it wrong would appreciate if someone could help me correct the logic.
You need to use SUM() to get sum of quantity and amount
SELECT pname, sold_to, date, SUM(pquantity), SUM(pamount)
FROM sales
WHERE DATE_FORMAT(date, '%Y-%m-%d') BETWEEN '$from' AND '$to'
GROUP BY pname, sold_to, date
ORDER BY sale_id DESC
I have a SQL query that I'm using to return the number of training sessions recorded by a client on each day of the week (during the last year).
SELECT COUNT(*) total_sessions
, DAYNAME(log_date) day_name
FROM programmes_results
WHERE log_date >= DATE_SUB(CURDATE(), INTERVAL 1 YEAR)
AND log_date <= CURDATE()
AND client_id = 7171
GROUP
BY day_name
ORDER
BY FIELD(day_name, 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY')
I would like to then plot a table showing these values as a percentage of the total, as opposed to as a 'count' for each day. However I'm at a bit of a loss as to how to do that without another query (which I'd like to avoid).
Any thoughts?
Use a derived table
select day_name, total_sessions, total_sessions / sum(total_sessions) * 100 percentage
from (
query from your question goes here
) temp
group by day_name, total_sessions
You can add the number of trainings per day in your client application to get the total count. This way you definitely avoid having a 2nd query to get the total.
Use the with rollup modifier in the query to get the total returned in the last row:
...GROUP BY day_name WITH ROLLUP ORDER BY ...
Use a subquery to return the overall count within each row
SELECT ..., t.total_count
...FROM programmes_results INNER JOIN (SELECT COUNT(*) as total_count FROM programmes_results WHERE <same where criteria>) as t --NO join condition
...
This will have the largest performance impact on the database, however, it enables you to have the total number in each row.
I have a sales table from which I select the total sales per month , highest sale , number of sale for all the months in the current year, using
select monthname(date),sum(amt_c),MAX(amt_c)
from sales where year(date)= year(now())
group by monthname(date) ;
I want to also select the customer who has done the highest purchase , i.e the customer correponding to the MAX(amt_c).
amt_c is the purchase done by the customer,
One way is a filtering join:
select filter.mn
, filter.sum_sales
, filter.max_sales
, sales.cust
from (
select monthname(date) as mn
, sum(amt_c) as sum_sales
, max(amt_c) as max_sales
from sales
where year(date) = year(now())
group by
mn
) filter
join sales
on monthname(sales.date) = filter.mn
and sales.amt_c = filter.max_sales
For more approaches, browse the greatest-n-per-group tag.
select v.monthname,
v.sum_amt_c,
v.max_amt_c,
count(s.amt_c) as num_of_amounts,
group_concat(s.cust) as customers
from (select monthname(date) as monthname,
sum(amt_c) as sum_amt_c,
max(amt_c) as max_amt_c
from sales
where date between concat(year(now()), '-01-01') and concat(year(now()), '-12-31')
group by monthname(date)) v
join sales s
on v.max_amt_c = s.amt_c
and v.monthname = monthname(s.date)
and s.date between concat(year(now()), '-01-01') and concat(year(now()), '-12-31')
group by v.monthname, v.sum_amt_c, v.max_amt_c
order by month(s.date)
This is similar to Andomar's answer however it provides the following benefits:
If your DATE field is indexed (it should be) the above query will use that index. You should not have criteria on a date field with a function applied to it. MySQL does not support function based indexes, so it is a given that year(date) is not indexed. date may be indexed, however.
This sorts the results by month # (1-12) but shows the month name.
In the event that the same 2+ customers are tied, this will list all of them, and show only one row for that month. You would otherwise potentially have 2, 3, 4+ rows for a single month in the event of a tie. This is done via MySQL's GROUP_CONCAT function.