MySQL sum a column based on another distinct column count - mysql

I need to get sum of hits based on distinct ip
So far, this is what I've come up with:
SELECT
COUNT(DISTINCT `ip`) AS `total`,
SUM(`hits`) AS `sum`
FROM `stats`.`stats`
WHERE `category`=?
GROUP BY `date`
Sample data:
| category | ip | hits | date |
| 11 | ip1 | 1000 | date1 |
| 11 | ip2 | 1000 | date1 |
| 11 | ip3 | 1000 | date1 |
| 11 | ip4 | 1000 | date1 |
| 11 | ip1 | 1000 | date1 |
Expected results:
ip=4
sum=4000
I am getting as
ip=4
sum=5000
But this is giving total ip hits instead if summing only distinct ip hits.
Please suggest a way to do this. I would prefer doing something like
SUM(CASE WHEN `ip` THAN `hits`)
//or
SUM(CASE WHEN IN(`ip`) THAN `hits`)
//or
SUM(CASE WHEN IF(`ip`) THAN `hits`)
instead of subquery as I need fast query.
Also using array_unique PHP side will be good for me.

You can do it like this:
SELECT count(s.ip) as cntIp,sum(s.hits) as sumHits
FROM(
SELECT DISTINCT t.ip,t.hits
FROM YourTable t) s
But it looks like the data you provided is not accurate, I see that you group by date, which means that the date equals and not like in your example date1,date2,date3...
So:
SELECT s.date,count(s.ip) as cntIp,sum(s.hits) as sumHits
FROM(
SELECT DISTINCT t.ip,t.hits,t.date
FROM YourTable t) s
GROUP BY s.date
EDIT:
SELECT s.date,count(s.ip) as cntIp,sum(s.hits) as sumHits
FROM(
SELECT t.ip,t.hits,t.date
FROM YourTable t
GROUP BY t.ip,t.hits,t.date) s
GROUP BY s.date

You need to write a subquery that returns the minimum hit value for each ip/date. Then you can sum these.
SELECT date, count(*) as sum, sum(minhits) as hits
FROM(
SELECT ip, date, MIN(hits) AS minhits
FROM stats
WHERE category = ?
GROUP BY ip, date) AS subquery
GROUP BY date

You can try this
SELECT
`ip`
COUNT(`ip`) AS `total`,
SUM(`hits`) AS `sum`
FROM
`stats`.`stats`
WHERE
`category`=?
GROUP BY
`date`,
`ip`

Related

Select last inserted value of each month for every year from DATETIME

I got a DATETIME to store when the values where introduced, like this example shows:
CREATE TABLE IF NOT EXISTS salary (
change_id INT(11) NOT NULL AUTO_INCREMENT,
emp_salary FLOAT(8,2),
change_date DATETIME,
PRIMARY KEY (change_id)
);
I gonna fill the example like this:
+-----------+------------+---------------------+
| change_id | emp_salary | change_date |
+-----------+------------+---------------------+
| 1 | 200.00 | 2018-06-18 13:17:17 |
| 2 | 700.00 | 2018-06-25 15:20:30 |
| 3 | 300.00 | 2018-07-02 12:17:17 |
+-----------+------------+---------------------+
I want to get the last inserted value of each month for every year.
So for the example I made, this should be the output of the Select:
+-----------+------------+---------------------+
| change_id | emp_salary | change_date |
+-----------+------------+---------------------+
| 2 | 700.00 | 2018-06-25 15:20:30 |
| 3 | 300.00 | 2018-07-02 12:17:17 |
+-----------+------------+---------------------+
1 won't appear because is an outdated version of 2
You could use a self join to pick group wise maximum row, In inner query select max of change_date by grouping your data month and year wise
select t.*
from your_table t
join (
select max(change_date) max_change_date
from your_table
group by date_format(change_date, '%Y-%m')
) t1
on t.change_date = t1.max_change_date
Demo
If you could use Mysql 8 which has support for window functions you could use common table expression and rank() function to pick row with highest change_date for each year and month
with cte as(
select *,
rank() over (partition by date_format(change_date, '%Y-%m') order by change_date desc ) rnk
from your_table
)
select * from cte where rnk = 1;
Demo
The below query should work for you.
It uses group by on month and year to find max record for each month and year.
SELECT s1.*
FROM salary s1
INNER JOIN (
SELECT MAX(change_date) maxDate
FROM salary
GROUP BY MONTH(change_date), YEAR(change_date)
) s2 ON s2.maxDate = s1.change_date;
Fiddle link : http://sqlfiddle.com/#!9/1bc20b/15

MySQL - count records and list people

I have table with results:
date | user_id | content
-----------------------------------------
2017-01-14 | 1 | lorem
2017-01-02 | 2 | dsfdf
2017-01-02 | 1 | asfds dsfsda
2017-01-27 | 3 | sdfdfds fsdf
And I want count row for all users and receive result like this:
user_id | count
-----------------------------------------
1 | 2
2 | 1
3 | 1
I try:
select distinct(user_id), count(*) from aso_repairs where date like '2017-01-%'
But this don't work ;-( Any help?
use the GROUP BY clause:
SELECT
user_id,
count(user_id)
FROM aso_repairs
WHERE
date LIKE '2017-01-%'
GROUP BY user_id
You shouldn't use count(*), at least in MySQL 3.23 this is far more expensive than count(somecolumn) although it yields the same result.
Add the missing group by clause:
SELECT
user_id, COUNT(*)
FROM
aso_repairs
WHERE
date LIKE '2017-01-%'
GROUP BY user_id;
Also, the like operator won't let you use any index if there was one on the date column. Consider providing the actual date boundaries:
SELECT
user_id, COUNT(*)
FROM
aso_repairs
WHERE
date BETWEEN '2017-01-01' AND '2017-01-31'
GROUP BY user_id;

MAX function in MySQL does not return proper key value

I have a table called tbl_user_sal:
| id | user_id | salary | date |
| 1 | 1 | 1000 | 2014-12-01 |
| 2 | 1 | 2000 | 2014-12-02 |
Now I want to get the id of the maximum date. I used the following query:
SELECT MAX(date) AS from_date, id, user_id, salary
FROM tbl_user_sal
WHERE user_id = 1
But it gave me this output:
| id | user_id | salary | from_date |
| 1 | 1 | 2000 | 2014-12-02 |
Which is correct as far as the max date being 2014-12-02, but the corresponding id is not correct. This happens for other records as well. I used order by to check but that was not successful either. Can anyone shed some light on this?
Note: Its not necessary that max date will have max id, according to my needs. Records can have max date but id may be older.
If you only want to retrieve that information for a single user, which you seem to, because of your WHERE clause, just use ORDER BY and LIMIT:
SELECT *
FROM tbl_user_sal
WHERE user_id = 1
ORDER BY date DESC
LIMIT 1
If you want to do that for every user, however, you will have to get a little bit fancier. Something like that should do it:
SELECT t2.id, user_id, date
--find max date for each user_id
FROM (SELECT user_id, MAX(date) AS date
FROM tbl_user_sal
GROUP BY user_id) AS t1
--join ids for each max date/user_id combo
JOIN tbl_user_sal AS t2
USING (user_id, date)
--limit to 1 id for every user_id
GROUP BY
user_id
You are missing group by clause Try this:
select max(awrd_date) as from_date,awrd_id
from tbl_user_sal
where awrd_user_id = 106
group by awrd_id
What I believe you should do here is have a subquery that pulls the max date, and your outer query looks for the row with that date.
It looks like this:
SELECT *
FROM myTable
WHERE date = (SELECT MAX(date) FROM myTable);
Additional things may need to be added if you want to search for a specific user_id, or get the largest date for each user_id, but this gives your expected results for this example here.
Here is the SQL Fiddle.

Mysql query extracting date + group by day

Simple question: Why does the following query not output perday?
SELECT FROM_UNIXTIME(`date`,"%Y-%m-%d") AS `perday`, COUNT(*) AS `count`
FROM `data`
WHERE `group` = 1
GROUP BY `perday`
Count gets outputted correctly, but perday stays empty.
The data table is like:
| id | group | date |
------------------------------------------------
| 1 | 1 | 2013-04-13 06:01:02 |
| 2 | 1 | 2013-04-13 14:24:18 |
| 3 | 2 | 2012-01-21 21:33:03 |
Ect.
Thanks!
EDIT:
Expected output:
| perday |
--------------
| 2013-04-13 |
| 2012-01-21 |
remove WHERE clause,
SELECT FROM_UNIXTIME(date,'%Y-%m-%d') AS perday,
SUM(`group` = 1) AS `count`
FROM data
GROUP BY FROM_UNIXTIME(date,'%Y-%m-%d')
if date is formatted as 2013-04-13 06:01:02, then why use FROM_UNIXTIME? Isn't it DATE_FORMAT instead?
SELECT DATE_FORMAT(date, '%Y-%m-%d') AS perday,
SUM(`group` = 1) AS `count`
FROM data
GROUP BY DATE(date)
ORDER BY date
This will display all available dates in the table.
SQLFiddle Demo
But if you want the selected group only,
SELECT DATE_FORMAT(date, '%Y-%m-%d') AS perday,
COUNT(*) AS `count`
FROM data
WHERE `group` = 1
GROUP BY DATE(date)
ORDER BY date
you may looking for this
SELECT DATE_FORMAT(`date`,"%Y-%m-%d") AS `perday`, COUNT(*) AS `count`
FROM `data`
WHERE `group` = 1
GROUP BY `perday`
DEMO HERE
MySQL DATE() takes the DATE part out from a DATETIME expression.As your Expected output this query is fine.
SELECT
DATE(`date`) AS `perday`,
COUNT(*) AS `count`
FROM `data`
GROUP BY `perday`

SUM a pair of COUNTs from two tables based on a time variable

Been searching for an answer to this for the better part of an hour without much luck. I have two regional tables laid out with the same column names and I can put out a result list for either table based on the following query (swap Table2 for Table1):
SELECT Table1.YEAR, FORMAT(COUNT(Table1.id),0) AS Total
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
Ideally I'd like to get a result that gives me a total sum of the counts by year, so instead of:
| REGION 1 | | REGION 2 |
| YEAR | Total | | YEAR | Total |
| 2010 | 5 | | 2010 | 1 |
| 2009 | 2 | | 2009 | 3 |
| | | | 2008 | 4 |
I'd have:
| MERGED |
| YEAR | Total |
| 2010 | 6 |
| 2009 | 5 |
| 2008 | 4 |
I've tried a variety of JOINs and other ideas but I think I'm caught up on the SUM and COUNT issue. Any help would be appreciated, thanks!
SELECT `YEAR`, FORMAT(SUM(`count`), 0) AS `Total`
FROM (
SELECT `Table1`.`YEAR`, COUNT(*) AS `count`
WHERE `Table1`.`variable` = 'Y'
GROUP BY `Table1`.`YEAR`
UNION ALL
SELECT `Table2`.`YEAR`, COUNT(*) AS `count`
WHERE `Table2`.`variable` = 'Y'
GROUP BY `Table2`.`YEAR`
) AS `union`
GROUP BY `YEAR`
You should use an UNION:
SELECT
t.YEAR,
COUNT(*) as TOTAL
FROM (
SELECT *
FROM Table1
UNION ALL
SELECT *
FROM Table2
) t
WHERE t.variable='Y'
GROUP BY t.YEAR;
Select year, sum(counts) from (
SELECT Table1.YEAR, FORMAT(COUNT(Table1.id),0) AS Total
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
UNION ALL
SELECT Table2.YEAR, FORMAT(COUNT(Table2.id),0) AS Total
FROM Table2
WHERE Table2.variable='Y'
GROUP BY Table2.YEAR ) GROUP BY year
To improve upon Shehzad's answer:
SELECT YEAR, FORMAT(SUM(counts),0) AS total FROM (
SELECT Table1.YEAR, COUNT(Table1.id) AS counts
FROM Table1
WHERE Table1.variable='Y'
GROUP BY Table1.YEAR
UNION ALL
SELECT Table2.YEAR, COUNT(Table2.id) AS counts
FROM Table2
WHERE Table2.variable='Y'
GROUP BY Table2.YEAR ) AS newTable GROUP BY YEAR