How to create a query for monthly total in MySQL? - mysql

I have the following DB.
CREATE TABLE IF NOT EXISTS `omc_order` (
`order_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`customer_id` int(10) unsigned NOT NULL,
`total` decimal(10,2) NOT NULL,
`order_date` datetime NOT NULL,
`delivery_date` datetime NOT NULL,
`payment_date` datetime NOT NULL,
PRIMARY KEY (`order_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=32;
I want to create a statistic page to see total payment and total order monthly.
In one page I want to display something like this.
Month Year Total Order Total Payment
Sep 09 800 760
Oct 09 670 876
Nov
...
...
Now I am not sure how to create query for this.
Could anyone give me some ideas how to approach this?

You can use the Mysql date and time functions to group the rows for each month and them sum them up. Something like this could be a starting point:
SELECT monthname(payment_date) AS Month,
year(payment_date) AS Year,
sum(total) AS 'Total Order',
sum(??) AS 'Total Payment'
FROM omc_order
ORDER BY payment_date
GROUP BY month(payment_date),
year(payment_date);
I'm not sure how you compute the values for Total Payment.
Edit: sum() is a MySQL function.

you need to Cast the datetime to a mount , then group by
SELECT SUM(foo), MONTH(mydate) DateOnly FROM a_table GROUP BY DateOnly;
see a close question :
MySQL/SQL: Group by date only on a Datetime column

The following should help you get started.
select sum(total) from omc_order group by month(order_date), year(order_date)

Related

Convert MySQL query to Laravel query builder code

I am working with agricultural product management system. I have a question regarding a MySQL query. I would like to know how to create the same query using Laravel query builder:
SELECT
vegitables.name, vegitables.image, vegitables.catagory,
AVG(price_wholesale),
SUM(CASE WHEN rank = 1 THEN price_wholesale ELSE 0 END) today,
SUM(CASE WHEN rank = 2 THEN price_wholesale ELSE 0 END) yesterday
FROM (
SELECT
veg_id, price_wholesale, price_date,
RANK() OVER (PARTITION BY veg_id ORDER BY price_date DESC) as rank
FROM old_veg_prices
) p
INNER JOIN vegitables ON p.veg_id = vegitables.id
WHERE rank in (1,2)
GROUP BY veg_id
This Output result get when run query in database:
Following two table are used to get today price yesterday price and price average get from each product.
CREATE TABLE `vegitables` (
`id` bigint(20) UNSIGNED NOT NULL,
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`image` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`catagory` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`total_area` int(11) NOT NULL COMMENT 'Total area of culativate in Sri Lanka (Ha)',
`total_producation` int(11) NOT NULL COMMENT 'Total production particular product(mt)',
`annual_crop_count` int(11) NOT NULL COMMENT 'how many time can crop pre year',
`short_dis` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `vegitables`
ADD PRIMARY KEY (`id`);
ALTER TABLE `vegitables`
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3;
COMMIT;
CREATE TABLE `old_veg_prices` (
`id` bigint(20) UNSIGNED NOT NULL,
`veg_id` int(11) NOT NULL,
`price_wholesale` double(8,2) NOT NULL,
`price_retial` double(8,2) NOT NULL,
`price_location` int(11) NOT NULL,
`price_date` date NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
ALTER TABLE `old_veg_prices`
ADD PRIMARY KEY (`id`);
ALTER TABLE `old_veg_prices`
MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=6;
COMMIT;
I try this site to convert to MySQL query to query builder code. But it show some error's could find it out. Any Way i want to run this code in Laravel with any method??
Your query will not return the data for yesterday and today; it will return the data for two most recent dates (e.g. if today is 2021-11-01 and most recent two dates for for carrots are 2021-10-25 and 2021-10-20 it will use those two dates). Using RANK() ... IN (1, 2) is also incorrect because it can return ranks such as 1 followed by 3 instead of 2.
To get today and yesterday prices you don't need window functions. Just use appropriate where clause and conditional aggregation:
SELECT vegitables.name
, vegitables.image
, vegitables.catagory
, AVG(old_veg_prices.price_wholesale) AS avgwholesale
, SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE - INTERVAL 1 DAY THEN old_veg_prices.price_wholesale END) AS yesterday
, SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE THEN old_veg_prices.price_wholesale END) AS today
FROM vegitables
INNER JOIN old_veg_prices ON vegitables.id = old_veg_prices.veg_id
WHERE old_veg_prices.price_date IN (CURRENT_DATE - INTERVAL 1 DAY, CURRENT_DATE)
GROUP BY vegitables.id -- other columns from vegitables table are functionally dependent on primary key
The Laravel equivalent would be:
DB::table('vegitables')
->Join('old_veg_prices', 'old_veg_prices.veg_id', '=', 'vegitables.id')
->whereRaw('old_veg_prices.price_date IN (CURRENT_DATE - INTERVAL 1 DAY, CURRENT_DATE)')
->select(
'vegitables.name',
'vegitables.image',
'vegitables.catagory',
DB::raw('AVG(old_veg_prices.price_wholesale) AS avgwholesale'),
DB::raw('SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE - INTERVAL 1 DAY THEN old_veg_prices.price_wholesale END) AS yesterday'),
DB::raw('SUM(CASE WHEN old_veg_prices.price_date = CURRENT_DATE THEN old_veg_prices.price_wholesale END) AS today')
)
->groupBy(
'vegitables.id',
'vegitables.name',
'vegitables.image',
'vegitables.catagory'
)
->get();
"Query builder" features of abstraction products often leave out some possible SQL constructs. I recommend you abandon the goal of reverse engineering SQL back to Laravel and simply perform the "raw" query.
Also...
rank() OVER (PARTITION BY veg_id ORDER BY price_date DESC) as rank
requires MySQL 8.0 (MariaDB 10.2).
And suggest you avoid the alias "rank" since that is identical to the name of a function.

Difficulty using LAG to get monthly progress percentage

I have the following table below and would like to take the monthly evolution (%) of total transactions per month. I researched the LAG function but could not understand very well.
I need the return of this query to be like this (Desired Output):
MONTH | TOTAL TRANSACTIONS | % EVOLUTION
----------------------------------------
09 | 45.561 | 0%
10 | 48.598 | 6.66%
UPDATE
% EVOLUTION = ((current value - previous value) / previous value) *
100
It is the formula I use to calculate the evolution of the number of transactions from one month to the previous month.
That is, a column with the previous month's total is required.
DDL
CREATE TABLE IF NOT EXISTS `campanha` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ano_mes` date DEFAULT NULL,
`nome` varchar(200) COLLATE utf8_unicode_ci NOT NULL,
`cpf` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`conta` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`valor` float(10,2) UNSIGNED ZEROFILL NOT NULL,
`transacoes` int(255) DEFAULT NULL,
PRIMARY KEY (`id`)
)
can anybody help me?
MySQL Version: 5.7.23 - MySQL Community Server
http://sqlfiddle.com/#!9/73f38f/2
MySQL 5.x does not support window functions such as LAG. You'll have to do it the old way. Based on table structure the following query should get you started:
SELECT yyyy
, mm
, txn_this_month
, (txn_this_month - (
SELECT SUM(transacoes)
FROM campanha
WHERE ano_mes >= STR_TO_DATE(CONCAT_WS('-', yyyy, mm, 1),'%Y-%c-%e') - INTERVAL 1 MONTH
AND ano_mes < STR_TO_DATE(CONCAT_WS('-', yyyy, mm, 1),'%Y-%c-%e')
)) / txn_this_month * 100 AS perc_change
FROM (
SELECT EXTRACT(YEAR FROM ano_mes) AS yyyy
, EXTRACT(MONTH FROM ano_mes) AS mm
, SUM(transacoes) AS txn_this_month
FROM campanha
GROUP BY EXTRACT(YEAR FROM ano_mes), EXTRACT(MONTH FROM ano_mes)
) AS x
ORDER BY yyyy, mm
The subquery inside select calculates sum for previous month for each row.

Get data grouped by 12 weeks period

I have a table with orders data:
CREATE TABLE `orders` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL DEFAULT '0',
`price` decimal(6,3) unsigned NOT NULL,
`created` datetime DEFAULT NULL,
`paid` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
I need to get price sum of orders in 12 weeks periods, where first period starts on a week when the very first order was paid, and each next period starts one week later than previous (this to have possibility to compare data in 12 weeks periods). So eventually there must be periods like 1-12, 2-13, etc.
Important detail: I can't use variables in query, because this query will be used in BI Tool, where queries with variables behave unexpected.
Did it next way:
SELECT `periods`.*, SUM(`orders`.`price`) AS `revenue`
FROM (SELECT DISTINCT FROM_DAYS(TO_DAYS(`paid`) - MOD(TO_DAYS(`paid`) -1, 7)) AS `period_start`,
(FROM_DAYS(TO_DAYS(`paid`) - MOD(TO_DAYS(`paid`) -1, 7)) + INTERVAL 12 WEEK) AS `period_end`
FROM `orders`
) AS `periods`
LEFT JOIN `orders` ON DATE(`orders`.`paid`) BETWEEN `periods`.`period_start` AND `periods`.`period_end`
GROUP BY `periods`.`period_end`
Small explanation: at first I define 12 week periods in subquery, using same table data. By doing this
DISTINCT FROM_DAYS(TO_DAYS(`paid`) - MOD(TO_DAYS(`paid`) -1, 7))
I shift paid value to the beginning of week.
With this
(FROM_DAYS(TO_DAYS(`paid`) - MOD(TO_DAYS(`paid`) -1, 7)) + INTERVAL 12 WEEK)
I add 12 weeks to the date means beginning of week.
Eventually I get result like this:
| period_start | period_end |
| 2015-07-19 | 2015-10-11 |
| 2015-07-26 | 2015-10-18 |
Then I simply join orders table and group data by end of period.
Looks like it does what I need.

Sum(count()) for last four months individually?

I have to find out tot(count) values with months for last 4 months individually how I can do this
table stucture was
CREATE TABLE `lime_survey_16579` (
`id` int(11) NOT NULL auto_increment,
`submitdate` datetime default NULL,
`lastpage` int(11) default NULL,
`startlanguage` varchar(20) collate utf8_unicode_ci NOT NULL,
`token` varchar(36) collate utf8_unicode_ci default NULL,
`16579X10X31` varchar(5) collate utf8_unicode_ci default NULLPRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=480 ;
here $survey = lime_survey_16579
and $temp= 16579X10X31
here 16579X10X31 has values like A1 A2 A3 ..
How I can do this to give output like
tot month
2 july
4 aug
6 sep
9 oct
Can anybody help me?
Please try below for all data:
SELECT count(id) as tot, MONTHNAME(submitdate) as `month`
FROM lime_survey_16579
GROUP BY month(submitdate)
ORDER BY month(submitdate)
To limit the data to last 4 month, please try below:
SELECT count(id) as tot, MONTHNAME(submitdate) as `month`
FROM lime_survey_16579
GROUP BY month(submitdate)
ORDER BY month(submitdate) DESC
LIMIT 4
Sel's solution is not going to work if you have data going into the previous year. Presumably, you want only the most recent "jul" record, not the sum of all of them.
For this, you can do:
SELECT count(id) as tot, MONTHNAME(submitdate) as `month`
FROM lime_survey_16579
GROUP BY monthname(submitdate), year(submitdate)
ORDER BY min(submitdate) DESC
LIMIT 4
You could optionally put the year on the SELECT line as well.
I replaced the month(submitdate) in the group by and order by clauses with other expressions. This avoids using a MySQL (mis) feature called hidden column, where columns not mentioned in group by clause and not aggregated are allowed in the select clause. Other SQL engines (as well as the standard) do not permit this.

MySQL Get rows between months

I'm trying to SELECT the visitors of my site per month for the current year.
For every different IP/user_agent combination there will be added a row per minute. To track the hits and the unique visitors.
My scheme looks like this:
CREATE TABLE `stats` (
`id` int(11) unsigned NOT NULL auto_increment,
`domain` varchar(40) NOT NULL,
`ip` varchar(20) NOT NULL,
`user_agent` varchar(255) NOT NULL,
`domain_id` int(11) NOT NULL,
`date` timestamp NOT NULL default CURRENT_TIMESTAMP,
`referrer` varchar(400) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
Now i would like to get all the unique visitors for all the months of a given year.
But i would like to make the unique visitors only unique for 24 hours. So not for the whole month.
It would be possible to just use date >= NOW() - INTERVAL 1 MONTH), but this will jump to 2008 Dec after 2009 Jan. So it should only show the months of a given year.
Are there function to do the same for a month (count the visitors per week, so 4 rows with the first until the fourth week)?
Thanks!
You want to get the number of unique visitors for each site per month?
Something like this should work:
SELECT COUNT(*), domain_id, m, y FROM
(
SELECT ip, user_agent, COUNT(ID) AS hits, domain_id,
DAY(date) as d, MONTH(date) as m, YEAR(date) as y
FROM `stats`
GROUP BY domain_id, ip, d, m, y
) AS tb
GROUP BY tb.m, tb.y
First it groups by day in the subquery, then it groups again by month in the surrounding query.
I'm not entirely sure what your intention was, but you should be able to adapt this technique for your purpose.
(edit: added year component to query)