Oracle SQL how to find count less than avg - sql

my code is like :
SELECT
number,
name,
count(*) as "the number of correct answer"
FROM
table1 NATURAL JOIN table2
WHERE
answer = 'T'
GROUP BY
number,
name
HAVING
count(*) < avg(count(*))
ORDER BY
count(*);
Here I want to find the group with count less than the average number of count for each group, but here I failed to use HAVING or WHERE, could anyone help me?
How can I only select the 1 name1 2 since avg of count is (2+6+7)/3 = 5 and only 2 is less than avg.
number name count
1 name1 2
2 name2 6
3 name3 7

I would advise you to never use natural joins. They obfuscate the query and make the query a maintenance nightmore.
You can use window functions:
SELECT t.*
FROM (SELECT number, name,
COUNT(*) as num_correct,
AVG(COUNT(*)) OVER () as avg_num_correct
FROM table1 JOIN
table2
USING (?). -- be explicit about the column name
WHERE answer = 'T'
GROUP BY number, name
) t
WHERE num_correct < avg_num_correct;
As with your version of the query, this filters out all groups that have no correct answers.

I would place your current query logic into a CTE, and then tag on the average count in the process:
WITH cte AS (
SELECT number, name, COUNT(*) AS cnt,
AVG(COUNT(*)) OVER () AS avg_cnt
FROM table1
NATURAL JOIN table2
WHERE answer = 'T'
GROUP BY number, name
)
SELECT number, name, cnt AS count
FROM cte
WHERE cnt < avg_cnt;
Here we are using the AVG() function as an analytic function, with the window being the entire aggregated table. This means it will find the average of the counts per group, across all groups (after aggregation). Window functions (almost) always evaluate last.

Related

count(*) and having not selecting for same date

I have a small doubt on regards how to organize a group_by.
I have this report that lists different we_date for each employee_payroll. one employee payroll can have records on multiple we_dates.
I want to select only when an employee_payroll has more than 4 occurences (disregarding the date column)
I understand that I need to do it either with a having count(employee_payroll) > 4 or a sub-query,
however when I try to do the having it asks me to group by using the date column, and this doesn't return the count per employee_payroll I need. (If I add a count(employee_payroll) I receive 1 in all rows, but I cannot not group by the date field. what am I doing wrong?
want to select only when an employee_payroll has more than 4 occurences (disregarding the date column)
You would use window functions:
select e.*
from (select e.*, count(*) over (partition by employee_payroll) as cnt
from employee e
) e
where cnt >= 4;
Explicit aggregation is probably not the best way to return this result.
This is hard to tell without the actual error you are getting that asks you to group by we_date, but in theory this should be what you have to do:
SELECT employee_payroll
FROM table
GROUP BY employee_payroll
HAVING count(employee_payroll) > 4;
You can first get employees with > 4 occurances. Then , only select those employee rows.
;WITH CTE_EmployeeWithGreaterThanFourOccurance (
SELECT Employee_Payroll, COUNT(*) AS cnt
FROM Employee
GROUP BY Employee_Payroll
HAVING COUNT(*) > 4
)
SELECT *
FROM Employee AS e
INNER JOIN CTE_EmployeeWithGreaterThanFourOccurance AS c
ON c.Employee_Payroll = e.Employee_Payroll

Filter by number of occurrences in a SQL Table

Given the following table where the Name value might be repeated in multiple rows:
How can we determine how many times a Name value exists in the table and can we filter on names that have a specific number of occurrances.
For instance, how can I filter this table to show only names that appear twice?
You can use group by and having to exhibit names that appear twice in the table:
select name, count(*) cnt
from mytable
group by name
having count(*) = 2
Then if you want the overall count of names that appear twice, you can add another level of aggregation:
select count(*) cnt
from (
select name
from mytable
group by name
having count(*) = 2
) t
It sounds like you're looking for a histogram of the frequency of name counts. Something like this
with counts_cte(name, cnt) as (
select name, count(*)
from mytable
group by name)
select cnt, count(*) num_names
from counts_cte
group by cnt
order by 2 desc;
You need to use a GROUP BY clause to find counts of name repeated as
select name, count(*) AS Repeated
from Your_Table_Name
group by name;
If You want to show only those Which are repeated more than one times. Then use the below query which will show those occurrences which are there more than one times.
select name, count(*) AS Repeated
from Your_Table_Name
group by name having count(*) > 1;

Calculate difference between two dates and count the number of occurrences

I am trying to calculate the difference between two dates and in the same query trying to count the frequency of occurence.
SELECT DATEDIFF(day,[Date1],[Date2]) AS 'Mydate'
, count ([Mydate])
FROM Table1
group
by 'Mydate'
I am expecting the query to calculate and count but getting an error msg "Each GROUP BY expression must contain at least one column that is not an outer reference."
what I am expecting is, something like this:
Mydate Count
0 5
1 4
2 5
Can someone help me please? Thanks
First of all this doesn't look like MySQL rather SQL Server. Secondly you can't use the alias in Count() function like that. Rather say count(*)
SELECT DATEDIFF(day,[Date1],[Date2]) AS 'Mydate',
Count (*)
FROM Table1
GROUP BY DATEDIFF(day,[Date1],[Date2])
You cannot group by an alias:
SELECT 'Mydate', Cnt
FROM (SELECT DATEDIFF(day, [Date1], [Date2]) AS 'Mydate',
Count(*) Cnt
FROM Table1) T1
GROUP BY 'Mydate'

Adding count in select query

I am trying to find a query that would give me a count of another table in the query. The problem is that I have no idea what to set where in the count part to. As it is now it will just give back a count of all the values in that table.
Select
ID as Num,
(select Count(*) from TASK where ID=ID(Also tried Num)) as Total
from ORDER
The goal is to have a result that reads like
Num Total
_________________
1 13
2 5
3 22
You need table aliases. So I think you want:
Select ID as Num,
(select Count(*) from TASK t where t.ID = o.ID) as Total
from ORDER o;
By the way, ORDER is a terrible name for a table because it is a reserved work in SQL.
You can do it as a sub query or a join (or an OVER statement.)
I think the join is clearest when you are first learning SQL
Select
ID as Num, count(TASK.ID) AS Total
from ORDER
left join TASK ON ORDER.ID=TASK.ID
GROUP BY ORDER.ID

adding count( ) column on each row

I'm not sure if this is even a good question or not.
I have a complex query with lot's of unions that searches multiple tables for a certain keyword (user input). All tables in which there is searched are related to the table book.
There is paging on the resultset using LIMIT, so there's always a maximum of 10 results that get withdrawn.
I want an extra column in the resultset displaying the total amount of results found however. I do not want to do this using a separate query. Is it possible to add a count() column to the resultset that counts every result found?
the output would look like this:
ID Title Author Count(...)
1 book_1 auth_1 23
2 book_2 auth_2 23
4 book_4 auth_.. 23
...
Thanks!
This won't add the count to each row, but one way to get the total count without running a second query is to run your first query using the SQL_CALC_FOUND_ROWS option and then select FOUND_ROWS(). This is sometimes useful if you want to know how many total results there are so you can calculate the page count.
Example:
select SQL_CALC_FOUND_ROWS ID, Title, Author
from yourtable
limit 0, 10;
SELECT FOUND_ROWS();
From the manual:
http://dev.mysql.com/doc/refman/5.1/en/information-functions.html#function_found-rows
The usual way of counting in a query is to group on the fields that are returned:
select ID, Title, Author, count(*) as Cnt
from ...
group by ID, Title, Author
order by Title
limit 1, 10
The Cnt column will contain the number of records in each group, i.e. for each title.
Regarding second query:
select tbl.id, tbl.title, tbl.author, x.cnt
from tbl
cross join (select count(*) as cnt from tbl) as x
If you will not join to other table(s):
select tbl.id, tbl.title, tbl.author, x.cnt
from tbl, (select count(*) as cnt from tbl) as x
My Solution:
SELECT COUNT(1) over(partition BY text) totalRecordNumber
FROM (SELECT 'a' text, id_consult_req
FROM consult_req cr);
If your problem is simply the speed/cost of doing a second (complex) query I would suggest you simply select the resultset into a hash-table and then count the rows from there while returning, or even more efficiently use the rowcount of the previous resultset, then you do not even have to recount
This will add the total count on each row:
select count(*) over (order by (select 1)) as Cnt,*
from yourtable
Here is your answare:
SELECT *, #cnt count_rows FROM (
SELECT *, (#cnt := #cnt + 1) row_number FROM your_table
CROSS JOIN (SELECT #cnt := 0 AS variable) t
) t;
You simply cannot do this, you'll have to use a second query.