Grouping by number of occurrences of a repeatable value in Oracle SQL - sql

Lets assume we have a table like this.
id name value
1 x 12
2 x 23
3 y 47
4 x 18
5 y 29
6 z 45
7 y 67
Doing a normal group by name would yield us
select name,count(*) from table group by name;
name count(*)
x 3
y 3
z 1
I want to get the reverse.. ie. grouping the number of names that occur a set number of times. I want my output to be
count number of elements occuring count times
1 1
3 2
Is it possible to do this using just a single query? Another way is to use a temp table but I dont want to do that.
Thanks

You need one more group by:
select cnt, count(*), min(name), max(name)
from (select name, count(*) as cnt
from table
group by name
) n
group by cnt
order by 1;
I do these types of histogram queries all the time. The min() and max() provide sample data. This is useful to understand outliers and unexpected values.

You can GROUP BY twice, e.g.
with
Names as (
select name as name,
count(1) as cnt
from MyTable
group by name)
select count(1),
cnt
from Names
group by cnt

Related

SQL need to compare rows count values

I have a query that returns the ID, Name and count of the number of times an ID has been entered to the table.
SELECT
ID,
NAME,
COUNT(*) count
FROM
TABLE
GROUP BY
NAME, ID, CASE_DETAIL_ID
HAVING
COUNT(*) > 1;
This returns the following data:
ID
NAME
COUNT
123
HAT
10
123
UMBRELLA
10
123
TOWEL
10
123
WATER
8
555
HAT
3
555
UMBRELLA
10
555
TOWEL
10
555
WATER
10
322
UMBRELLA
5
322
TOWEL
20
322
WATER
20
I want to be able to query the row with a count of less than what the other rows with the same ID have. How can I do this? So that the end result is:
ID
NAME
COUNT
FULL COUNT
123
WATER
8
10
555
HAT
3
10
322
UMBRELLA
5
20
There are multiple IDs that we store and I only want the rows/names that have a count less than the rows with the same IDs have.
I have also tried -
WITH x AS
(SELECT ID, NAME, COUNT(*) count
FROM FRT.CASE_DETAIL_HISTORY
GROUP BY
NAME,
ID,
CASE_DETAIL_ID)
SELECT x.ID, t.NAME, X.COUNT, MIN(x.count)
FROM x
JOIN FRT.CASE_DETAIL_HISTORY t
on t.ID= x.ID
GROUP BY x.ID, t.ID, X.COUNT
However, this doesnt give me what I am looking for. I only want rows returned if the name's count doesnt match the 'mode' count of the ID.
I also have tried the below but keep facing errors:
WITH COUNT_OF_ROWS AS
(SELECT ID, NAME, COUNT(*) count
FROM TABLE
GROUP BY NAME, ID, CASE_DETAIL_ID
HAVING COUNT(*) >= 1),
MINIMUM AS
(SELECT COUNT_OF_ROWS.ID, COUNT_OF_ROWS.NAME,
MIN(COUNT_OF_ROWS.COUNT) MINI
FROM COUNT_OF_ROWS
JOIN TABLE CD on CD.ID = COUNT_OF_ROWS.ID
GROUP BY COUNT_OF_ROWS.ID, COUNT_OF_ROWS.NAME
)
select distinct COUNT_OF_ROWS.*, MINIMUM.MINI
from minimum, count_of_rows
where minimum.mini != count_of_rows.count;
Some sample data would help but you can use a CTE, and select the lowest using min() something like this:
WITH x AS(
SELECT t.id, t.nametext, COUNT(*) as count
FROM table t
GROUP BY id, t.nametext, CASE_DETAIL_ID
), y as(
SELECT x.id, MIN(x.[COUNT]) as mincount
FROM x
GROUP BY x.id
)
select y.id, x.nametext, y.mincount
from y
join x
on x.[COUNT] = y.mincount
and x.id = y.id
Or it can be done using top 1 and order by like this:
SELECT TOP 1 id, name, COUNT(*) as count
FROM TABLE
WHERE ID = 123
GROUP BY NAME, ID, CASE_DETAIL_ID
ORDER BY count DESC
But bare in mind that as this would select only the first row, this would only work with the where clause because it would always only return 1 row.
While if you use the CTE option it would work also if you want per id, without where id = 123.

How to get the smallest unique integer from a table in SQLite

I have a table that has two columns, name and number. I'd like to get the smallest unique number from the provided table. for example
name
number
john
1
abbey
3
afton
2
mike
1
lucas
5
jack
2
jake
4
tony
3
For example, the smallest value here is 1 but the smallest unique value is 4
How could I make a query in SQLite that can do that?
I did see this post but it's not what I want
Edit: This is the code I tried
Select a.name, a.number
From Result a
Having count(a.smallest) = 1
Group By a.smallest;
It returned "Error: near line XX: near "Group": syntax error"
I also tried
Select a.name, a.number
From Result a
Where count(a.smallest) = 1
Group By a.smallest;
But it returned "Error: near line XX: misuse of aggregate: count()"
You may try aggregating your table by the number, restricting to numbers only appearing once, and then retaining the smallest number:
SELECT number
FROM yourTable
GROUP BY number
HAVING COUNT(*) = 1
ORDER BY number
LIMIT 1;
Using ROW_NUMBER:
SELECT *
FROM (SELECT a.*, COUNT(*) OVER(PARTITION BY number) AS cnt
FROM Result a) sub
WHERE cnt = 1
ORDER BY number
LIMIT 1;
Output:
name number cnt
jake 4 1
db<>fiddle demo
You can group by number and set the condition in the HAVING clause that the number is unique.
Then pick the smallest number with MIN() window function:
SELECT DISTINCT MIN(number) OVER () AS min_number
FROM tablename
GROUP BY number
HAVING COUNT(*) = 1;
See the demo.

Grouping over multiple columns and counting distinct over different groups

Given this data
month
id
1
x
1
x
1
y
2
z
2
x
2
y
My output should be
month
distinct_id
total_id
1
2
3
2
3
3
How can I achieve this in a single query?
I tried this query
SELECT TO_CHAR(DOCDATE,'MON') MON
,COUNT(DISTINCT T.MOB_MTCHED_LYLTY_ID) OVER() SHARE
from data
group by 1
but this is giving me an error
select month,
count(distinct id) distinct_id,
count(id) total_id
from data
group by month;
SELECT [Month], COUNT(DISTINCT id) as dist_id, COUNT(id) as count_id
FROM data
GROUP BY Month
Also i should say:
About your code - don't use OVER if it's not necessary
Don't use picutes in your question like you use it know - provide data in a small table is better

Get Count Based on Combinations of Values from Second Column

I have a table format like below:
Id Code
1 A
1 B
2 A
3 A
3 C
4 A
4 B
I am trying to get count of code combinations like below:
Code Count
A,B 2 -- Row 1,2 and Row 6,7
A 1 -- Row 3
A,C 1 -- Row 4
I am unable to get the combination result. All I can do is group by but I am not getting count of IDs based in combinations.
You need to aggregate the rows, somehow, and do that twice. The code looks something like this:
select codes, count(*) as num_ids
from (select id, group_concat(code order by code) as codes
from t
group by id
) id
group by code;
group_concat() might be spelled listagg() or string_agg() depending on the database.
In SQL Server, use string_agg():
select codes, count(*) as num_ids
from (select id, string_agg(code, ',') within group (order by code) as codes
from t
group by id
) id
group by code;

sql count instances of a field - microsoft sql server management studio

I want a table like below. I have first 2 columns available. I want the count column to have incremental count of values in column name
name marks count
a 23 1
b 43 2
c 54 3
d 64 4
a 12 2
b 3 2
a 4 3
For SQL Server:
SELECT name,
marks,
Row_number()
OVER (
PARTITION BY name
ORDER BY (SELECT 1)) AS [Count]
FROM MyTable
The rows aren't guaranteed to arrive in any particular order unless you have some way of ordering like the results above that you haven't told us about. There's also no way of knowing which order the ROW_NUMBER will be assigned to all those values with the same name - again - if there is a specific order you'd like to use then use that instead of the (SELECT 1) above.
SELECT name,
marks,
count (id),
FROM MyTable
group by name, marks