SQL Min and Count - sql

What I'm trying to achieve is to display the count number of books in categories
Where Count(Category) > Minimum number in Count(Category)
Example;
If categories are
A = 1
b = 2
c = 3
D = 1
E = 1
I'm trying to show the categories which are > 1 using MIN.
The error I'm getting is:
ORA-00935: group function is nested too deeply
SELECT Count(Category),
Category
From Books
Having Count((Category) > MIN(Count(Category)
Group BY Category

Looking for something like this:
Select Count(Category),
Category
From Books
Group BY Category
Having Count(Category) > (Select Min(cnt)
from (Select Count(Category) AS cnt
From Books
Group By Category))
This will select all categories having a count that is greater than the minimum count among all categories.

Another way is to rank by count starting with the lowest (ties are assigned the same rank) and to only select rows with rank greater than 1:
select * from (
select count(*) cnt, category,
rank() over (order by count(*)) rn
from books
group by category
) t where rn > 1

This should do it:
SELECT Category, CategoryCount from
(SELECT rownum as r, Category, Count(*) as CategoryCount
From Books
Group BY Category
Order by CategoryCount asc)
Where r > 1;

Giorgos's answer is the correct one. It can be rearranged (and made slightly more efficient) using subquery factoring:
with ctg (category, categ_count) as (
select category, count(*)
from books
group by category
)
select category, categ_count
from ctg
where categ_count > (select min(categ_count) from ctg);

Related

select value based on max of other column

I have a few questions about a table I'm trying to make in Postgres.
The following table is my input:
id
area
count
function
1
100
20
living
1
200
30
industry
2
400
10
living
2
400
10
industry
2
400
20
education
3
150
1
industry
3
150
1
education
I want to group by id and get the dominant function based on max area. With summing up the rows for area and count. When area is equal it should be based on max count, when area and count is equal it should be based on prior function (i still have to decide if education is prior to industry or vice versa). So the result should be:
id
area
count
function
1
300
50
industry
2
1200
40
education
3
300
2
industry
I tried a lot of things and maybe it's easy, but i don't get it. Can someone help to get the right SQL?
One method uses row_number() and conditional aggregation:
select id, sum(area), sum(count),
max(function) over (filter where seqnum = 1) as function
from (select t.*,
row_number() over (partition by id order by area desc) as seqnum
from t
) t
group by id;
Another method uses ``distinct on`:
select id, sum(area) over (partition by id) as area,
sum(count) over (partition by id) as count,
function
from t
order by id, area desc;
Use a scalar sub-query for "function".
select t.id, sum(t.area), sum(t.count),
(
select "function"
from the_table
where id = t.id
order by area desc, count desc, "function" desc
limit 1
) as "function"
from the_table as t
group by t.id order by t.id;
SQL Fiddle
you can use sum as window function:
select distinct on (t.id)
id,
sum(area) over (partition by id) as area,
sum(count) over (partition by id) as count,
( select function from tbl_test where tbl_test.id = t.id order by count desc limit 1 ) as function
from tbl_test t
This is how you get the function for each group based on id:
select id, function
from yourtable yt1
left join yourtable yt2
on yt1.id = yt2.id and yt1.area < yt2.area
where yt2.area.id is null;
(we ensure that no yt2 exists that would be of the same id but of higher areay)
This would work nicely, but you might have several max areas with different values. To cope with this isue, let's ensure that exactly one is chosen:
select id, max(function) as function
from yourtable yt1
left join yourtable yt2
on yt1.id = yt2.id and yt1.area < yt2.area
where yt2.area.id is null
group by id;
Now, let's join this to our main table;
select yourtable.id, sum(yourtable.area), sum(yourtable.count), t.function
from yourtable
join (
select id, max(function) as function
from yourtable yt1
left join yourtable yt2
on yt1.id = yt2.id and yt1.area < yt2.area
where yt2.area.id is null
group by id
) t
on yourtable.id = t.id
group by yourtable.id;

select two grouped by columns but only select row with the highest COUNT()

I have a table that consists of three columns - UPC, ATTRIBUTE, STORE_NUM. I have 10 stores and 2 UPCs at each with different ATTRIBUTEs.
Every store either has either attribute X or Y. I group by UPC and ATTRIBUTE and get the count of stores.
SELECT [UPC], [ATTRIBUTE], COUNT([STORE_NUM]) AS [COUNT]
FROM TABLEA
GROUP BY [UPC], [ATTRIBUTE]
Yields this:
UPC ATTRIBUTE COUNT
1 X 8
1 Y 2
2 X 1
2 Y 9
And I want to select UPC and ATTRIBUTE with the highest count. My desired output would be this:
UPC ATTRIBUTE
1 X
2 Y
I can't figure out how to reach this desired outcome.
You can use window functions with aggregation:
SELECT *
FROM (SELECT [UPC], [ATTRIBUTE], COUNT(*) AS [COUNT],
ROW_NUMBER() OVER (PARTITION BY UPC ORDER BY COUNT(*) DESC) as seqnum
FROM TABLEA
GROUP BY [UPC], [ATTRIBUTE]
) x
WHERE seqnum = 1;
Use RANK() if you want duplicates in the event of ties.
Use row_number and a subquery:
SELECT UPC, ATTRIBUTE
FROM (
SELECT UPC, ATTRIBUTE, ROW_NUMBER() OVER (PARTITION BY UPC ORDER BY a_count DESC) as rn
FROM ( SELECT [UPC],[ATTRIBUTE],COUNT([STORE_NUM]) AS [a_COUNT]
FROM TABLEA
GROUP BY [UPC],[ATTRIBUTE]
) t
) q
WHERE q.rn = 1

Finding top count of a value in a table using SQL

I'm looking for a way to find the top count value of a column by SQL.
If for example this is my data
id type
----------
1 A
1 B
1 A
2 C
2 D
2 D
I would like the result to be:
1 A
2 D
I'm looking for a way to do it without groping by the column I count (type in the example)
Thanks
Statistically, this is called the "mode". You can calculate it using window functions:
select id, type, cnt
from (select id, type, count(*) as cnt,
row_number() over (partition by id order by count(*) desc) as seqnum
from t
group by id, type
) t
where seqnum = 1;
If there are ties, then an arbitrary value is chosen from among the ties.
You are looking for the statistic mode (the most often ocurring value):
select id, stats_mode(type)
from mytable
group by id
order by id;
Not all DBMS support this however. Check your docs, wheher this function or a similar one is available in your DBMS.
Just GROUP BY id, type and keep the rows with the maximum counter:
select id, type
from tablename
group by id, type
having count(*) = (
select count(*) from tablename group by id, type order by count(*) desc limit 1
)
See the demo
Or
select id, type
from tablename
group by id, type
having count(*) = (
select max(t.counter) from (select count(*) counter from tablename group by id, type) t
)
See the demo

SELECT MAX of COUNT

I have a table "well". It contains a column app_rate_unit (type: nvarchar).
My goal is to count every distinct value in the table and let the DBMS (MS Server 2005) give me the most occurring one.
This is my code:
SELECT MAX(app_rate_unit) AS MAX_APP
FROM (SELECT app_rate_unit, COUNT(*) AS co
FROM dbo.well AS w
GROUP BY app_rate_unit
) AS derivedtbl_1
The poblem with it is however, that my DBMS actually delivers the lowest count to me.
SideQuestion: How do I filter for a foreign key (in the table) and NOT NULL (in app_rate_unit) when counting?
select top 1 app_rate_unit, count(*) from dbo.well
group by app_rate_unit
order by count(*) desc
Try this
SELECT
COUNT(app_rate_unit)AS MAX_APP ,
app_rate_unit
FROM
dbo.well
WHERE
app_rate_unit IS NOT NULL
GROUP BY
app_rate_unit
ORDER BY
MAX_APP DESC
The above script will give you the count and the item. You can change the count if you are not sure only one item will have the maximum number of occurrence.
select top 1 count(*) as co from dbo.well as w group by app_rate_unit
order by count(*) desc
In PostgreSQL we can write query which using max of count as
select max(count) from (
select count(id) from Table _name group by created_by,status_id having status_id = 6 ) as Alias
eg
select max(count) from (
select count(id) from orders group by created_by,status_id having status_id = 6 ) as foo

sql query to find the duplicate records

what is the sql query to find the duplicate records and display in descending, based on the highest count and the id display the records.
for example:
getting the count can be done with
select title, count(title) as cnt from kmovies group by title order by cnt desc
and the result will be like
title cnt
ravi 10
prabhu 9
srinu 6
now what is the query to get the result like below:
ravi
ravi
ravi
...10 times
prabhu
prabhu..9 times
srinu
srinu...6 times
If your RDBMS supports the OVER clause...
SELECT
title
FROM
(
select
title, count(*) OVER (PARTITION BY title) as cnt
from
kmovies
) T
ORDER BY
cnt DESC
You can do it in a single query:
Select t.Id, t.title, z.dupCount
From yourtable T
Join
(select title, Count (*) dupCount
from yourtable
group By title
Having Count(*) > 1) z
On z.title = t.Title
order By dupCount Desc
This query uses the Group By and and Having clauses to allow you to select (locate and list out) for each duplicate record. The As clause is a convenience to refer to Quantity in the select and Order By clauses, but is not really part of getting you the duplicate rows.
Select
Title,
Count( Title ) As [Quantity]
From
Training
Group By
Title
Having
Count( Title ) > 1
Order By
Quantity desc
select distinct title, (
select count(title)
from kmovies as sub
where sub.title=kmovies.title) as cnt
from kmovies
group by title
order by cnt desc
You can't do it as a simple single query, but this would do:
select title
from kmovies
where title in (
select title
from kmovies
group by title
order by cnt desc
having count(title) > 1
)