MYSQL count of count? - mysql

I have a mysql table like:
id, visitorid, pageid
When a visitor hits the website it stores their visitor id and the page id as a row.
I am trying to extract the number of visitors who hit the website exactly X times. (for a chart). so how many visit just one page, how many visit 2 pages...
so far I have:
SELECT COUNT(visid),visid FROM vislog GROUP BY visid ORDER BY COUNT(visid) DESC
But I don't know how to do the next part of counting the counts.
Is it possible to do as a MySQL query?

You can wrap your query inside another one:
SELECT
cnt AS page_visits
, COUNT(*) AS number_of_visitors
FROM
( SELECT
COUNT(*) AS cnt --- use: COUNT(DISTINCT page_id)
--- for a different count
FROM vislog
GROUP BY visid
) AS grp
GROUP BY cnt
ORDER BY number_of_visitors ;
or (I suppose this makes more sense for passing the numbers to a chart), remove the ORDER BY which is the same as putting:
ORDER BY cnt ;

One way to do it is to wrap this query into another one:
SELECT COUNT(visid) FROM (
SELECT COUNT(visid) AS cvisid, visid
FROM vislog
GROUP BY visid
HAVING cvisid = 2) AS c
But I think you need to get the histogram of visits: this can be done with PHP (assuming the query is the same as in the question):
$results = array();
// query preparation skipped, as it's obviously done by the OP himself
while ($row = $sth->fetch()) {
$count = $row['cvisid'];
if (isset($results[$count])) {
$results[$count]++;
}
else {
$results[$count] = 1;
}
}
Or with MySQL itself:
SELECT cvisid,
COUNT(cvisid) AS cnt
FROM (
SELECT visid,
COUNT(visid) AS cvisid
FROM vislog
GROUP BY visid ) AS c
GROUP BY cvisid

Raina77ow (2nd reply) returned a clean solution in his third block of code
SELECT cvisid,
COUNT(cvisid) AS cnt
FROM (
SELECT visid,
COUNT(visid) AS cvisid
FROM vislog
GROUP BY visid ) AS c
GROUP BY cvisid
thank you

Try using following query
SELECT COUNT(a.page_visits) AS no_of_visitors, a.page_visits AS page_count
FROM(
SELECT COUNT(DISTINCT pageid) AS page_visits
FROM vislog
GROUP BY visid) AS a
GROUP BY a.page_visits;
Hope it helps...

I could solve it this way:
SELECT cnt, COUNT(cnt) FROM (
SELECT COUNT(visid) as cnt FROM vislog GROUP BY visid
) x GROUP BY cnt ORDER BY cnt ASC
The little x is important.

Related

Add the result of SELECT query in another SELECT query

This is the result of a UNION of two SELECT
SELECT count(*) FROM
((SELECT session_id_current_user from test.tws_analytics
WHERE (add_date BETWEEN '2022-05-15' AND '2022-05-15') AND ((pathURL='vues/login.php' AND name_current_user='') OR (pathURL='' AND searchURL='?job=forgotten' AND name_current_user=''))
AND session_id_current_user NOT IN
(SELECT session_id_current_user from test.tws_analytics
WHERE (pathURL <> 'vues/login.php' AND searchURL <> '?job=forgotten') AND add_date BETWEEN '2022-05-15' AND '2022-05-15' order by session_id_current_user)
order by session_id_current_user)
UNION
(SELECT name_current_user from test.tws_analytics where add_date BETWEEN '2022-05-15' AND '2022-05-15' AND name_current_user IS NOT NULL AND name_current_user <> ''))
AS tem
The result is 11.
What I want to do is to select this result with other columns like this :
SELECT count(session),count(name), [AND tem.count(*)] FROM ....
This is the general idea, though i didn't know how to implement it.
a simplified general answer would be
select * from (select count(*) numsessions from sessions), (select count(*) numusers from users)
this will give 2 different counts, i didn't include the logics that you provided, but that will need to be done inside the 2 subqueries.

get the most common value for each column

I'm attempting to create an SQL query that retrieves the total_cost for every row in a table. Alongside that, I also need to collect the most dominant value for both columnA and columnB, with their respective values.
For example, with the following table contents:
cost
columnA
columnB
target
250
Foo
Bar
XYZ
200
Foo
Bar
XYZ
150
Bar
Bar
ABC
250
Foo
Bar
ABC
The result would need to be:
total_cost
columnA_dominant
columnB_dominant
columnA_value
columnB_value
850
Foo
Bar
250
400
Now I can get as far as calculating the total cost - that's no issue. I can also get the most dominant value for columnA using this answer. But after this, I'm not sure how to also get the dominant value for columnB and the values too.
This is my current SQL:
SELECT
SUM(`cost`) AS `total_cost`,
COUNT(`columnA`) AS `columnA_dominant`
FROM `table`
GROUP BY `columnA_dominant`
ORDER BY `columnA_dominant` DESC
WHERE `target` = "ABC"
UPDATE: Thanks to #Barmar for the idea of using a subquery, I managed to get the dominant values for columnA and columnB:
SELECT
-- Retrieve total cost.
SUM(`cost`) AS `total_cost`,
-- Get dominant values.
(
SELECT `columnA`
FROM `table`
GROUP BY `columnA`
ORDER BY COUNT(*) DESC
LIMIT 1
) AS `columnA_dominant`,
(
SELECT `columnB`
FROM `table`
GROUP BY `columnB`
ORDER BY COUNT(*) DESC
LIMIT 1
) AS `columnB_dominant`
FROM `table`
WHERE `target` = "XYZ"
However, I'm still having issues figuring out how to calculate the respective values.
You might get close, if we want to get percentage values we can try to add COUNT(*) at subquery to get max count by columnA and columnB then do division by total count
SELECT
SUM(cost),
(
SELECT tt.columnA
FROM T tt
GROUP BY tt.columnA
ORDER BY COUNT(*) DESC
LIMIT 1
) AS columnA_dominant,
(
SELECT tt.columnB
FROM T tt
GROUP BY tt.columnB
ORDER BY COUNT(*) DESC
LIMIT 1
) AS columnB_dominant,
(
SELECT COUNT(*)
FROM T tt
GROUP BY tt.columnA
ORDER BY COUNT(*) DESC
LIMIT 1
) / COUNT(*) AS columnA_percentage,
(
SELECT COUNT(*)
FROM T tt
GROUP BY tt.columnB
ORDER BY COUNT(*) DESC
LIMIT 1
) / COUNT(*) AS columnB_percentage
FROM T t1
If your MySQL version supports the window function, there is another way which reduce table scan might get better performance than a correlated subquery
SELECT SUM(cost) OVER(),
FIRST_VALUE(columnA) OVER (ORDER BY counter1 DESC) columnA_dominant,
FIRST_VALUE(columnB) OVER (ORDER BY counter2 DESC) columnB_dominant,
FIRST_VALUE(counter1) OVER (ORDER BY counter1 DESC) / COUNT(*) OVER() columnA_percentage,
FIRST_VALUE(counter2) OVER (ORDER BY counter2 DESC) / COUNT(*) OVER() columnB_percentage
FROM (
SELECT *,
COUNT(*) OVER (PARTITION BY columnA) counter1,
COUNT(*) OVER (PARTITION BY columnB) counter2
FROM T
) t1
LIMIT 1
sqlfiddle
try this query
select sum(cost) as total_cost,p.columnA,q.columnB,p.columnA_percentage,q.columnB_percentage
from get_common,(
select top 1 columnA,columnA_percentage
from(
select columnA,count(columnA) as count_columnA,cast(count(columnA) as float)/(select count(columnA) from get_common) as columnA_percentage
from get_common
group by columnA)s
order by count_columnA desc
)p,
(select top 1 columnB,columnB_percentage
from (
select columnB,count(columnB) as count_columnB, cast(count(columnB) as float)/(select count(columnB) from get_common) as columnB_percentage
from get_common
group by columnB) t
order by count_columnB desc)q
group by p.columnA,q.columnB,p.columnA_percentage,q.columnB_percentage
so if you want to get the percent and dominant value you must make their own query like this
select top 1 columnA,columnA_percentage
from(
select columnA,count(columnA) as count_columnA,cast(count(columnA) as float)/(select count(columnA) from get_common) as columnA_percentage
from get_common
group by columnA)s
order by count_columnA desc
then you can join with the sum query to get all value you want
hope this can help you

order by with union in SQL is not working

Is it possible to order when the data comes from many select and union it together? Such as
In this statement, the vouchers data is not showing in the same sequence as I saved on the database, I also tried it with "ORDER BY v_payments.payment_id ASC" but won't be worked
( SELECT order_id as id, order_date as date, ... , time FROM orders WHERE client_code = '$searchId' AND order_status = 1 AND order_date BETWEEN '$start_date' AND '$end_date' ORDER BY time)
UNION
( SELECT vouchers.voucher_id as id, vouchers.payment_date as date, v_payments.account_name as name, ac_balance as oldBalance, v_payments.debit as debitAmount, v_payments.description as descriptions,
vouchers.v_no as v_no, vouchers.v_type as v_type, v_payments.credit as creditAmount, time, zero as tax, zero as freightAmount FROM vouchers INNER JOIN v_payments
ON vouchers.voucher_id = v_payments.voucher_id WHERE v_payments.client_code = '$searchId' AND voucher_status = 1 AND vouchers.payment_date BETWEEN '$start_date' AND '$end_date' ORDER BY v_payments.payment_id ASC , time )
UNION
( SELECT return_id as id, return_date as date, ... , time FROM w_return WHERE client_code = '$searchId' AND w_return_status = 1 AND return_date BETWEEN '$start_date' AND '$end_date' ORDER BY time)
Wrap the sub-select queries in the union within a SELECT
SELECT id, name
FROM
(
SELECT id, name FROM fruits
UNION
SELECT id, name FROM vegetables
)
foods
ORDER BY name
If you want the order to only apply to one of the sub-selects, use parentheses as you are doing.
Note that depending on your DB, the syntax may differ here. And if that's the case, you may get better help by specifying what DB server (MySQL, SQL Server, etc.) you are using and any error messages that result.
You need to put the ORDER BY at the end of the statement i.e. you are ordering the final resultset after union-ing the 3 intermediate resultsets
To use an ORDER BY or LIMIT clause to sort or limit the entire UNION result, parenthesize the individual SELECT statements and place the ORDER BY or LIMIT after the last one. See link below:
ORDER BY and LIMIT in Unions
(SELECT a FROM t1 WHERE a=10 AND B=1)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2)
ORDER BY a LIMIT 10;

How to write sql query to get items from range

I would like to get values without the smallest and the biggest ones, so without entry with 2 and 29 in column NumberOfRepeating.
My query is:
SELECT Note, COUNT(*) as 'NumberOfRepeating'
WHERE COUNT(*) <> MAX(COUNT(*))AND COUNT(*) <> MIN(COUNT(*))
FROM Note GROUP BY Note;
SELECT Note, COUNT(*) as 'NumberOfRepeating'
FROM Notes
GROUP BY Note
HAVING count(*) <
(
SELECT max(t.maxi)
FROM (select
Note, COUNT(Note) maxi FROM Notes
GROUP BY Note
) as t
)
AND
count(*) >
(
SELECT min(t.min)
FROM (select
Note, COUNT(Note) min FROM Notes
GROUP BY Note
) as t
)
try this code.
One method would use order by and limit, twice:
select t.*
from (select t.*
from t
order by NumberOfRepeating asc
limit 99999999 offset 1
) t
order by NumberOfRepeating desc
limit 99999999 offset 1;
Try this code,
Select * from Note where NumberOfRepeating < (select MAX(NumberOfRepeating) from Note ) AND NumberOfRepeating > (select MIN(NumberOfRepeating) from Note );
Here in the code, as in your table Note is the name of the table, and NumberOfRepeating is the column name, as in your table.
Try this. It should work
SELECT *
FROM ( SELECT Note, COUNT(*) as 'NumberOfRepeating'
FROM Notes
GROUP BY Note
ORDER BY NumberOfRepeating DESC
LIMIT 1, 2147483647
) T1
ORDER BY T1.NumberOfRepeating
LIMIT 1, 2147483647

SQL SCORE RANKING

I'm working with score ranking on my app for all user score. My problem is I don't know how to return one row for each stud_num.
My query:
SELECT * FROM score WHERE assess_type = 'professional' ORDER BY total_score DESC.
Result:
As you can see I have 3 stud_num and I only want one row per stud_num and the highest score of it.
You can use correlated query like this:
SELECT * FROM score t
WHERE t.assess_type = 'professional'
AND t.total_score = (select max(s.total_score)
from score s
where t.stud_num = s.stud_num)
group by stud_num
The option given by #sagi is good:
SELECT * FROM score t
WHERE t.assess_type = 'professional'
AND t.total_score = (select max(s.total_score)
from score s
where t.stud_num = s.stud_num)
group by stud_num
Another option would be to use an inner join and group by together.
The resulting query would become:
select * from score a
inner join (
SELECT stud_num, max(total_score) tscore FROM `score` group by stud_num) b
on a.stud_num = b.stud_num and total_score= tscore
group by a.stud_num
try it out at sqlfiddle
Use the MAX and GROUP BY functions like this:
SELECT score_id, stud_num, assess_type, total_item, MAX(total_score), average, date_taken
FROM score
WHERE assess_type = 'professional'
GROUP BY stud_num
ORDER BY 5 DESC
Here's my the ans:
SELECT score_id, stud_num, assess_type, total_item, MAX( total_score )
FROM score
WHERE assess_type = 'professional'
GROUP BY stud_num, total_item
ORDER BY MAX( total_score ) DESC