mysql GROUP BY with multiple columns - mysql

I have table where date is stored as 3 columns in the table, i.e as below
`periodYear`
`periodMonth`
`billDay`
Which is causing me problems, when i want to generate reports based on the DATE which is a combination of above three. for example
SELECT SUM(amount) as Total,
FROM invoice
WHERE `periodYear` = 2014,
GROUP BY `billDay`,`periodMonth`,`periodYear`
Can somebody help me to explain how to solve this problem ?
For example I want to list all the totals last year on daily base,
If it's a date column, I could have just group by date, but in this case I don't know how to do that, because if you group by billday,..,., then it going group based on the day not DATE.. you see what I mean ?

Try this,
SELECT SUM(amount) as Total FROM invoice WHERE `periodYear`=2014 GROUP BY CONCAT(periodYear, '-', periodMonth, '-', billDay);

You could just concatenate the values together and then group on that:
SELECT SUM(amount) as Total FROM invoice
WHERE periodYear=2014
GROUP BY CONCAT(billDay, '-', periodMonth, '-', periodYear)
Or if you would want to convert to and actual date format for easier sorting afterwards:
SELECT SUM(amount) as Total FROM invoice
WHERE periodYear=2014
GROUP BY CONCAT(periodYear,
'-',
LPAD(periodMonth, 2, '00'),
'-',
LPAD(billDay, 2, '00')
)

I think what you want is just the opposite of what you've tried.
SELECT SUM(amount) as 'Total'
FROM `invoice`
WHERE `periodYear` = 2014
GROUP BY `periodYear`, `periodMonth`, `billDay`
This will group first by year, then by month, then by day. Biggest to smallest.

Related

Incrementing MySql variable by SUM() not correct

I am trying to put together a query that groups records by date along with a total for that particular date (there can be multiple entries in a day) but I also need a running total that I intended on using a MySQL variable for. My issue is that the cumulative total column seems to contain the SUM() for just that date.
So this works fine for the daily totals
SELECT
YEAR(log_at) as year,
MONTH(log_at) as month,
DAY(log_at) as day,
SUM(ev) as dailyTotal,
count(*) as count
FROM tracks
WHERE user_id = 1
GROUP BY year, month, day
ORDER BY year, month, day ASC
Add what I thought was going to be a fairly simple variable in there to keep track of the running total
SET #cumulative := 0;
SELECT
YEAR(log_at) as year,
MONTH(log_at) as month,
DAY(log_at) as day,
SUM(ev) as dailyTotal,
#cumulative := #cumulative + sum(ev) AS cumulative,
count(*) as count
FROM tracks
WHERE user_id = 1
GROUP BY year, month, day
ORDER BY year, month, day ASC
And the cumulative variable just contains the total for that day. But if I change it to increment by 1 instead of the SUM() it seems to work correctly
Any advice for achieving the desired behaviour is greatly appreciated!
You have to first create the whole selection and only then do your cumulative-stuff because you can't append the sum of a column of your GROUP BY at the same time (I don't really know why dough)
SELECT
`year`,
`month`,
`day`,
`dailyTotal`,
#cum := #cum + `dailyTotal` as `cumulative`,
`count`
FROM
(
SELECT
YEAR(log_at) as year,
MONTH(log_at) as month,
DAY(log_at) as day,
SUM(ev) as dailyTotal,
count(*) as count
FROM tracks
WHERE user_id = 1
GROUP BY year, month, day
ORDER BY year, month, day ASC
) a
JOIN (SELECT #cum := 0) b
I tested it with a bit less intensive tables... maybe I got this one wrong here. But I hope you get the theory.

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`

How to find which year do values tend to increase in ? in SQL

Basically I have a table like this:
Table Time:
ID.......Date
1......08/26/2016
1......08/26/2016
2......05/29/2016
3......06/22/2016
4......08/26/2015
5......05/23/2015
5......05/23/2015
6......08/26/2014
7......04/26/2014
8......08/26/2013
9......03/26/2013
The query should return like this
Year........CountNum
2016........4
2015........3
To find out which year does its value tend to increase in. I notice that I want to display the years that have more values (number of row in this case) than the previous year.
What I've done so far
SELECT Year, count(*) as CountNum
FROM Time
GROUP BY Year
ORDER BY CountNum DESC;
I don't know how to get the year from date format. I tried year(Date) function, but I got Null data.
Please help!
It should works fine.
select year(date), count(*) as countNum
from time
group by year(date)
order by countNum
Join the grouped data to itself with 1 year offset:
select
a.*
from
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) a
left join
(
select year(`Date`) as _year, count(*) as _n
from time group by 1
) b
on a._year = b._year-1
where a._n > b._n
order by 1

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(*).