Nested Query returns nothing - mysql

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

Related

SQL SUM() across a subquery

I have a Ledger table with this schema:
LedgerId (int,not null)
Timestamp (datetime, not null)
CostCenter (int, not null)
Payee (varchar(50), not null)
Type (varchar(3),not null)
Category (varchar(24), not null)
Amount (decimal(8,2) not null)
Tag (varchar(30),null)
Memo (varchar(150), null)
where I record expense transactions for a small business.
At year's end I have to issue a form 1099 to the IRS for any contractor who received more than $600. I run the following query (thanks to StackExchange!) to get this:
SELECT Payee as Name, SUM(Amount)as Total FROM Ledger
where (convert(date,timestamp) < convert(date,'2019-01-01'))
and (convert(date,timestamp) > convert(date,'2017-12-31'))
and category like '%Contract%'
group by Payee having SUM(amount) > 600
order by Payee
This is great, and gives me a list of each contractor and the total amount for 2018.
What I would like now is a query that will give me the total amount I have spent for these contractors in 2018 (also for IRS, form 1096).
If I use this query as a subquery to obtain this total amount I get errors. How do I go about totaling all this contractor expense?
Are you saying this doesn't work?
select sum(total)
from (select Payee as Name, SUM(Amount) as Total
from Ledger
where timestamp < '2019-01-01' and
timestamp >= '2018-01-01' and
category like '%Contract%'
group by Payee
having sum(amount) > 600
) l;
You shouldn't need date conversions for the logic you want to implement.

Mysql Query - How get first row of each category and column and its comparison?

I need a mysql query to find Which week of month is the most expensive week (week_of_month) and how much in this week
is spent (WOM_AMT) than other weeks of month each year against each supplier
This query will give you max spent per week:
SELECT supplier, year, week_of_month, MAX(wom_amt)
FROM table t
GROUP BY supplier, year, week_of_month;
Now, in order to compare this amount against the SUM of the rest, you can wrap this query into outer query and calculate the SUM, e.g.:
SELECT a.supplier, a.year, a.week_of_month, a.wom_amt as 'max_amount',
(SELECT SUM(wom_amt) FROM table WHERE supplier = a.supplier AND year = a.year
AND week_of_month = a.week_of_month AND wom_amt != a.wom_amt) as 'other_amounts'
FROM (SELECT supplier, year, week_of_month, MAX(wom_amt)
FROM table t
GROUP BY supplier, year, week_of_month) a;
I think that what you are looking for is MAX and GROUP BY.
Something like this should work (not tested):
SELECT
`Supplier`,
`Year`,
`Week_Of_Month`,
MAX(`WOM_AMT`) AS WOM_AMT
FROM `table`
GROUP BY `Supplier`, `Year`

Merging multiple MySQL SELECT statements calculating fields

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

Name of customer with highest sale monthwise

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.

MySQL group by day with datetime mixing same dates from different months

I'm trying to group posts from same day, the problem is that 2/20 gets grouped with 3/20 (20 = 20)
How can this be fixed?
This is my current code:
select day(Date), count(*) from Posts WHERE shopID != '' group by shopID, day(Date)
You need to group by every piece that might be different. So add MONTH(Date) and even YEAR(Date) depending on the scope of your query.
select DAY(Date), count(*) from Posts WHERE shopID != '' group by shopID, YEAR(Date), MONTH(Date), DAY(Date)
You could also group this way: UNIX_TIMESTAMP(date(date)), instead of grouping by year, month and day separately
select date(date), count(*) from Posts
WHERE shopID != ''
group by shopID, UNIX_TIMESTAMP(date(date))
Note you'll have to also take the other date data in the select statement to be able to recognize which month/year the day belongs to. If you don't you'll get a lot of day numbers and counts, but the day numbers will be repeated for each month/year.
That's why I used date(date), count(*).