Count all unique records - php

I have a database with the following format:
myTable
productgroupID | productID | views | date
1 | 10 | 25 | 2013-05-23
4 | 105 | 15 | 2013-05-23
7 | 60 | 65 | 2013-05-23
7 | 60 | 55 | 2013-05-22
7 | 60 | 45 | 2013-05-21
Now I want to sum all views of a product in the moth May.
Result should be:
productgroupID | productID | viewed | month
7 | 60 | 165 | 2013-05-01
1 | 10 | 25 | 2013-05-01
4 | 105 | 15 | 2013-05-01
I tried the query below, but this gives me all views of a specific productgroupID. But I need the sum of the unique productgroupID & productID.
SELECT COUNT( views ) AS viewed, productgroupID FROM product_stats_daily GROUP BY productgroupID

If you want the views totaled, then you can use the sum() aggregate function and then you can group by the month and year for the date:
select productGroupId,
productId,
sum(views) viewed,
month(date) Month,
year(date) Year
from myTable
group by productGroupId, productId, month(date), year(date);
See SQL Fiddle with Demo
You could also use Date_Format to get the date in the format that you want:
select productGroupId,
productId,
sum(views) viewed,
DATE_FORMAT(date, '%Y-%m-01') date
from myTable
group by productGroupId, productId, DATE_FORMAT(date, '%Y-%m-01')
See SQL Fiddle with Demo

COUNT will count number of rows while SUM will sum up value of retrieved rows.
So your query becomes:
SELECT SUM( views ) AS viewed, productgroupID
FROM product_stats_daily
GROUP BY productgroupID

There's probably a more elegant way to force the date to the beginning of the month, but this should work:
SELECT
ProductGroupID,
ProductID,
SUM(views) AS viewed,
DATE_FORMAT(date, '%Y-%m-01') AS Month
FROM myTable
GROUP BY
ProductGroupID,
ProductID,
DATE_FORMAT(date, '%Y-%m-01')

Related

Select SUM "separately" for the past 30 days

I have a MySQL table which is as follows
------------------------------------------------
| id | user_id | day | value |
| INT(11) | INT(11) | INT(8) | DECIMAL(5,2) |
------------------------------------------------
Day is (Ymd) number like this: 20191012
I want to grab the SUM(value) for Today and the past 29 days separately (30 days, based on day column)
I thought of a loop like this
for($i=0;$i<=30;$i++)
{
$query = "SELECT SUM(value) FROM table WHERE day=".date('Ymd', strtotime("-{$i} days"));
}
But how can I achieve this more efficiently?
Any help is appreciated.
You could use Group By to fetch it with a single MySQL-Query
SELECT day, SUM(value) FROM table GROUP BY day WHERE day >= ".date('Ymd', strtotime("-29 days"));
It should work because your day field is a number and will increase everyday so you can just compare it with gte
Expected output will be
---------------------------
| day | SUM(value) |
| INT(8) | |
---------------------------
| 20191012 | 15.25 |
---------------------------
| 20191011 | 29.13 |
---------------------------
| ... | ... |
---------------------------
J4I: If there are days without values in your dataset, the missing "day-row" is also missing in the output so it could be that there are less than 30 result-rows.
This query will work for any version of MySQL. It creates a temporary numbers table with the numbers from 0-29, then uses that to compute a list of days from today to 29 days earlier. This is then LEFT JOINed to the data table to compute the sum per day, with 0 sums where there is no data for a given day:
SELECT d.day, COALESCE(SUM(value), 0)
FROM (SELECT DATE_FORMAT(CURDATE() -INTERVAL n10.n * 10 + n.n DAY, '%Y%m%d') AS day
FROM (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3
UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6
UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) n
CROSS JOIN (SELECT 0 AS n UNION ALL SELECT 1 UNION ALL SELECT 2) n10) d
LEFT JOIN `table` t ON t.day = d.day
GROUP BY d.day
Demo on dbfiddle

MySQL PHP select rows count in date range

I have a MySQL table for product orderings named TABLE1.
Date means the date purchase has been made
The table has other columns that currently have no influence.
PRODUCT_ID | DATE | other columns
3 |2018-02-01 | other values
3 |2018-02-03 | other values
3 |2018-02-07 | other values
3 |2018-02-07 | other values
3 |2018-03-02 | other values
I know that the first time the product 3 has been ordered, is 2018-02-01
SELECT DATE FROM TABLE1 WHERE PRODUCT_ID = '3' ORDER BY DATE ASC LIMIT 1
How do I select count of product orderings per day within range of 2018-02-01 and 2019-03-16 (today) so that I could get a table like that:
DATE | ORDERS_PER_DAY
2018-02-01 | 1
2018-02-02 | 0
2018-02-03 | 1
...
2018-02-07 | 2
...
2018-03-02 | 1
...
2018-03-15 | 0
2018-03-16 | 0
Thanks for help!
You can simply use GROUP BY clause to do it.
SELECT `DATE`, COUNT(`PRODUCT_ID`) AS ORDERS_PER_DAY
FROM TABLE1
WHERE `DATE` BETWEEN '2018-02-01' AND CURDATE()
GROUP BY `DATE`
This query will result in filtering the records on your required date range and then grouping it by each day where there is data.
My syntax may not be exactly correct, but could you try something like this using the GROUP BY clause.
SELECT DATE, COUNT(*) AS ORDERS_PER_DAY
FROM TABLE1
GROUP BY DATE, PRODUCT_ID
HAVING PRODUCT_ID = '3'
you can read more about this here: https://dev.mysql.com/doc/refman/8.0/en/group-by-handling.html

How to get data by end date of every month of year?

This is sample data in my table
id_item | qty | t_in | t_out | created_at
1 5 1 0 2018-07-05 10:41:00
1 5 1 0 2018-08-03 10:41:00
1 5 0 1 2018-08-05 10:41:00
1 5 1 0 2018-09-05 10:41:00
1 5 1 0 2018-09-20 10:41:00
1 5 0 1 2018-10-31 10:41:00
My expected result will be
id_item | qty | year | month
1 5 2018 07
1 5 2018 08
1 15 2018 09
1 10 2018 10
What i have tried it works, but not desired output when want to group by montly
$date = '2018-10-31'
$test = Model::whereDate('created_at','<=',$date)->select(DB::raw('(SUM(CASE T_IN WHEN 1 THEN qty ELSE qty * - 1 END)) as total'))->groupBy('id_item')->get();
Raw queries to get the quantity for one month
Select id_item,
(SUM(CASE T_IN WHEN 1 THEN qty ELSE qty * - 1 END)) as total
from transactions
where DATE(created_at) <= 2018-10-31
group by id_item
Worst case
$last_day_of_month = [//list of last day of each month]
//then using loop to get qty of each month refer to the raw queries above
From the query above, i only able to get one line of record. I also tried to group by month and year but incorrect result caused of the date condition. How can i include multiple <= $date condition and group it accordingly to get desired output?
Any idea or is that possible to make it? Thanks.
It is a Rolling Sum problem. In newer versions of Mariadb/MySQL, it can be solved using Window Functions with Frames. However, you don't have that available.
We can rather solve this using user-defined variables. In a Derived table, we first determine the total change in qty for a month. Then, we use this result-set to calculate "final qty" at the end of a month, by adding up the previous month (row)'s qty with current month (row)'s qty_change.
I have also extended the query to consider the cases when there are more than one id_item values.
Try the following Raw query:
SELECT
#roll_qty := CASE WHEN #id_itm = dt.id_item
THEN #roll_qty + dt.qty_change
ELSE dt.qty_change
END AS qty,
#id_itm := dt.id_item AS id_item,
dt.year,
dt.month
FROM
(
SELECT
t.id_item,
SUM(t.qty * t.t_in - t.qty * t.t_out) AS qty_change,
YEAR(t.created_at) AS `year`,
LPAD(MONTH(t.created_at), 2, '0') AS `month`
FROM your_table AS t
GROUP BY t.id_item, `year`, `month`
ORDER BY t.id_item, `year`, `month`
) AS dt
CROSS JOIN (SELECT #roll_qty := 0,
#id_itm := 0
) AS user_init_vars;
| id_item | year | month | qty |
| ------- | ---- | ----- | --- |
| 1 | 2018 | 07 | 5 |
| 1 | 2018 | 08 | 5 |
| 1 | 2018 | 09 | 15 |
| 1 | 2018 | 10 | 10 |
View on DB Fiddle
If you are going to use variables, you need to do it correctly. MySQL does not guarantee the order of evaluation of expressions in a SELECT. So, a variable should not be assigned in one expression and then used in another.
This makes for complicated expressions, but it is possible:
select yyyy, mm, total,
(#t := if(#ym = concat_ws('-', yyyy, mm), #t + total,
#ym := concat_ws('-', yyyy, mm), total
)
) as running_total
from (select year(created_at) as yyyy, month(created_at) as mm,
id_item,
sum(case T_IN when 1 then qty else - qty end) as total
from transactions
where created_at < '2018-11-01'
group by id_item
order by id_item, min(created_at)
) i cross join
(select #ym := '', #n := 0);

How to get Sale data of every month of a year

I'm trying to get Sale Data of every month of particular year, but I'm having a problem building a query for it.
Here is What I've tried
SELECT COUNT(`id`) AS `total_order`
FROM orders
WHERE date BETWEEN ? AND ?
GROUP BY `total_order`
HERE is How my table look like
----------------------------------------
| id | item_name | amount | time |
| 21 | item_1 | 10 | 1506675630 |
| 22 | item_2 | 30 | 1506675630 |
| 23 | item_3 | 70 | 1506675630 |
| 24 | item_4 | 100 | 1506675630 |
----------------------------------------
Now here is what i want from the query
1 - Total Sales amount made from the beginning of the year till today.
2 - Sales made Today
3 - Sales made in Last Month
4 - Sales Made in Last 3 month
5 - Sales Made in Last 6 Month
6 - Total Number of Sales made in every month of this particular year
for e.g -
January - 20
Feb -100
March - 200 & so on.
How can i achieve this complex query?
SELECT `id` AS `Order_Number`, item_name, SUM(Amount)
FROM orders
WHERE time >= '01/01/17'
GROUP BY date
That would give you your first result. Try the others and let me know what you get
This answers your first question
SELECT
DATE_FORMAT(FROM_UNIXTIME(time), '%Y-%m') as interval,
COUNT(*) AS sales_made,
SUM(amount) AS sales_amount
FROM orders
WHERE
time BETWEEN UNIX_TIMESTAMP('2017-01-01') AND UNIX_TIMESTAMP('2018-01-01')
GROUP BY 1
ORDER BY 1;
Here is what i think would work:
for the first 5 queries try something like this.
SELECT SUM(amount)
FROM orders
WHERE DATE_FORMAT(FROM_UNIXTIME(`orders.time`), '%Y-%m-%d') BETWEEN ? AND ?
And for the last one you'll need :
SELECT DATE_FORMAT(FROM_UNIXTIME(`orders.time`), '%Y-%m-%d') AS 'date', SUM(amount)
FROM orders
WHERE date between ? AND ?
GROUP BY DATE_FORMAT(date, '%Y%m')
You can try without the FROM_UNIXTIME if it doesnt work.

Counting renewals during count of subscription sold

I've a table in which write every subscription sold of my magazine, like this:
USERID | DATE |
31 | 2011-09-22 |
54 | 2011-09-22 |
59 | 2011-09-23 |
11 | 2011-10-02 |
88 | 2011-10-05 |
31 | 2011-10-06 |
17 | 2011-10-12 |
54 | 2011-10-15 |
31 | 2011-11-05 |
54 | 2011-11-12 |
Now, for statistical purpose, i need to having an outcome in which i see, for every single month, how many subscriptions i've sold and how many users have already bought once this.
For instance, if we look the datas on top, i should have an outcome likie this:
DATE | SOLD | RENEWAL
09 | 3 | 0
10 | 5 | 1
11 | 2 | 2
I can to group the subscriptions sold monthly, but i can't add the "renewal" info.
SELECT COUNT( * ) AS sold, MONTH(date) FROM table_sold WHERE date >= CURDATE() - INTERVAL 13 MONTH GROUP BY YEAR( date ) , MONTH( date ) ORDER BY date ASC LIMIT 1,15
In this way i only have an outcome like this:
DATE | SOLD
09 | 3
10 | 5
11 | 2
I've tried several option, with subquery, union and so on, but without successful.
There is to consider that the table has 70.000 entries and a query with a hard scan could be a problem.
In your opinion is there a way in mysql or i've to take the idea to make it in php?
Here is an idea. Look at the first date for each user. Then count renewals in every month that is not the first date:
select year(date), month(date), count(*) as sold,
sum(case when date <> firstdate then 1 else 0 end) as renewals
from subscriptions s join
(select userid, min(date) as firstdate
from subscriptions s
group by userid
) su
on s.userid = su.userid
group by year(date), month(date)
order by year(date), month(date);

Categories