MySQL Grouping Twice - mysql

I have a database structure of:
ip | yid | date
Where ip represents a user's IP and yid is a specific page ID. I'm trying to group by the ip and yid column, which I have done below. But then I need to group those results by the yid. So it would be grouping it into:
yid | count
Where count is the number of times that the page was called limiting 1 call per ip address.
Right now I have:
SELECT `ip`, `yid`, `time`, MAX(`time`), count(*)
FROM mp_downloads
GROUP BY CONCAT(`ip`, `yid`), `yid`
ORDER BY count(*) DESC
But it's not grouping the page ids after it groups by the distinct yid & ip combo.

Try This using nested query:
select temp.*, count(*) from
(SELECT `ip`, `yid`, `time`, MAX(`time`)
FROM mp_downloads
GROUP BY CONCAT(`ip`, `yid`))temp group by temp.yid;

The normative pattern for getting a count of ip addresses that have accessed a (yid) would be:
SELECT d.yid
, COUNT(DISTINCT d.ip) AS ip_count
, MAX(d.date) AS latest_time
FROM mp_downloads d
GROUP BY d.yid
For best performance, you'd want a suitable index, e.g.
... ON mp_downloads (yid, ip, date)
There's no need to group by an expression that concatenates two columns. There's no need for a derived table (inline view) or a subquery. If you don't need the latest_time, you can omit that expression.

Related

MySQL: count no duplicates of another column when using UNION ALL

The following query works great to count and get the total sum of visitors to my page.
SELECT id, COUNT(id) AS count
FROM visits
WHERE status <> 'test'
GROUP BY id
UNION ALL
SELECT 'SUM' id, COUNT(id)
FROM visits
WHERE status <> 'test'
But inside the visits table I have a column called IP where I store the IP of the visitors. I want to change the above query so that visits with the same IP are not counted (I only want to count unique IPs). How can I do it?
I have tried HAVING COUNT(IP) > 1 but it doesn't work.
Thanks!!!

SELECT count of subquery before applying LIMIT (clickhouse)

I have a subquery that aggregates some UNION ALL selects. Over that I prepare the SELECT to create cross-tab and limit it to let's say 20. I would like to be able to retrieve the total COUNT of sub query results before I am limiting them in main query. This is for the purpose of trying to build a pagination that receives the total number of records and then the specific page record grid.
Sample query:
SELECT
name,
sumIf(metric_value, metric_name = 'data') AS data,
sumif(....
FROM
(SELECT
name, metric_name, SUM(metric_value) as metric_value
FROM
(SELECT
name, 'data' AS metric_name, SUM(data) AS metric_value
FROM
table
WHERE
date > '2017-01-01 00:00:00'
GROUP BY
name
UNION ALL
SELECT
name, 'data' AS metric_name, SUM(data) AS metric_value
FROM
table2
WHERE
date > '2017-01-01 00:00:00'
GROUP BY
name
UNION ALL
SELECT
name, 'data' AS metric_name, SUM(data) AS metric_value
FROM
table3
WHERE
date > '2017-01-01 00:00:00'
GROUP BY
name
UNION ALL
.
.
.)
GROUP BY
name, metric_name)
GROUP BY
name
ORDER BY
name ASC
LIMIT 0,20;
The first subselect returns tons of data, so I thought I can count it and return as one column value, or row and it would propagate to main select that limits 20 results. Because I need to know the entire set of results but don;t want to call the same query twice without limit and with limit just to get COUNT. There are at least 12 UNION ALL third level sub selects, so why waste resources. I am looking to try generic SQL solutions not necessarily related to ClickHouse
I was thinking of using count(*) OVER (), however that is not supported, so if thats only option I know I need to run query twice.
The first thing that one should mention is that nobody is usually interested in the exact number of pages on a query. It can be easily estimated and almost no one will care how exact is the estimation. However, if you have a link to the last page in your GUI, people will often click to link just to see whether it works.
Nevertheless, there are cases when an analyst should visit all the pages, and then the GUI should display the exact amount of work. A good news is that in that latter case, a better strategy is to cache a snapshot of the whole results table and counting the rows in the table becomes not a problem anymore.
I mean, it makes sense to discuss with the customers whether they really need it, because unneeded full scans many times per day may have effect on the database load and billing sums.
Anyway, if you still need to estimate the number of rows, you can simplify the query just to count the number of rows. As I understand this is something like:
SELECT SUM(cnt) as row_count
FROM (
SELECT COUNT(DISTINCT name) as cnt FROM table1 WHERE date > ...
UNION ALL
SELECT COUNT(DISTINCT name) as cnt FROM table2 WHERE date > ...
...
) as counts;
or if data is a constant metric name
SELECT COUNT(DISTINCT name) as row_count
FROM (
SELECT DISTINCT name FROM table1 WHERE date > ...
UNION ALL
SELECT DISTINCT name FROM table2 WHERE date > ...
...
) as names;

How to get a field value and all related elements by using that field value in the same query?

I have a table that has these fields:
clickId, ip, date
I need to get all dates in which an user (with an IP like 192.168.0.55) did clicks, and for every date how many clicks he did.
How can I do this with one single MySql query?
you can just group by the ip and date. if it is a datetime you need to group by DATE(date)
SELECT ip, DATE(date), COUNT(*) as num_clicks
FROM your_table
GROUP BY ip, DATE(date)
this will be for all ip addresses by a specific date. you can also specify a specific ip address in a WHERE clause
aka. WHERE ip = "192.168.0.55"
Use GROUP BY along with an aggregation function.
SELECT date, COUNT(*) AS click_count
FROM YourTable
WHERE IP = '192.168.0.55'
GROUP BY date

MySQL wrong results with GROUP BY and ORDER BY

I have a table user_comission_configuration_history and I need to select the last Comissions configuration from a user_id.
Tuples:
I'm trying with many queries, but, the results are wrong. My last SQL:
SELECT *
FROM(
SELECT * FROM user_comission_configuration_history
ORDER BY on_date DESC
) AS ordered_history
WHERE user_id = 408002
GROUP BY comission_id
The result of above query is:
But, the correct result is:
id user_id comission_id value type on_date
24 408002 12 0,01 PERCENTUAL 2014-07-23 10:45:42
23 408002 4 0,03 CURRENCY 2014-07-23 10:45:41
21 408002 6 0,015 PERCENTUAL 2014-07-23 10:45:18
What is wrong in my SQL?
This is your query:
SELECT *
FROM (SELECT *
FROM user_comission_configuration_history
ORDER BY on_date DESC
) AS ordered_history
WHERE user_id = 408002
GROUP BY comission_id;
One major problem with your query is that it uses a MySQL extension to group by that MySQL explicitly warns against. The extension is the use of other columns in the in theselect that are not in the group by or in aggregation functions. The warning (here) is:
MySQL extends the use of GROUP BY so that the select list can refer to
nonaggregated columns not named in the GROUP BY clause. This means
that the preceding query is legal in MySQL. You can use this feature
to get better performance by avoiding unnecessary column sorting and
grouping. However, this is useful primarily when all values in each
nonaggregated column not named in the GROUP BY are the same for each
group. The server is free to choose any value from each group, so
unless they are the same, the values chosen are indeterminate.
So, the values returned in the columns are indeterminate.
Here is a pretty efficient way to get what you want (with "comission" spelled correctly in English):
SELECT *
FROM user_commission_configuration_history cch
WHERE NOT EXISTS (select 1
from user_commission_configuration_history cch2
where cch2.user_id = cch.user_id and
cch2.commission_id = cch.commission_id and
cch2.on_date > cch.on_date
) AND
cch.user_id = 408002;
Here's one way to do what your trying. It gets the max date for each user_ID and commissionID and then joins this back to the base table to limit the results to just the max date for each commissionID.
SELECT *
FROM user_comission_configuration_history A
INNER JOIN (
SELECT User_ID, Comission_Id, max(on_Date) mOn_Date
FROM user_comission_configuration_history
Group by User-Id, Comission_Id
) B
on B.User_ID = A.User_Id
and B.Comission_Id = A.Comission_ID
and B.mOnDate=A.on_date
WHERE user_id = 408002
ORDER BY on_Date desc;

How to Get Row Count Depending on Column Values using MySQL

I am querying a mysql table and want results group by date, and one column name is type. There are two value for the type call and email. I want to find count for call and email for each day.
Find the SQL Fiddle here
I am trying with this query. Which only gets me total counts:
SELECT Date(date) date,
COUNT(type) total,
COUNT(type='email') emails,
COUNT(type='call') calls
from leads
where user_id = 1
GROUP BY Date(date)
Use SUM() instead. The type='email' in the function returns either 0 (false) or 1 (true).
SELECT Date(date) date,
COUNT(type) total,
SUM(type='email') emails,
SUM(type='call') calls
from leads
where user_id = 1
GROUP BY Date(date)