Is there an analytic function for count in oracle sql - sql

select manager, count(*) over (partition by manager) cnt
from dbtable
group by manager
This will provide me the count of manager but if I need a count of senior_manager how will I get it?
|--------------------|------------------|
| Manager |Senior_Manager |
|--------------------|------------------|
| John |Arpit |
| John |govind |
| John |olive |
| Domnic |kelvin |
| Domnic |paul |
|--------------------|------------------|
Result
John 3
Domnic 2

Your code returns "1" for all managers -- because it counts the number of rows after the group by.
If you want to count the number of rows in the table for a given manager, then you want aggregation, not analytic functions:
Select manager, count(*) as cnt
from dbtable
group by manager;
I'm not sure if this answers your question, but it at least addresses the issue that the your query does not do much that is useful.
EDIT:
For the revised question, it simply seems:
Select senior_manager, count(*) as cnt
from dbtable
group by senior_manager;

The result you wanted can be retrieved by
select manager, count(*) over (partition by manager) cnt
from dbtable
This means each manager will be associated with the count of rows in the partition where {manager} value equals that exact manager. According to the table above this is what you expect to get.

Your example:
select manager, count(*) over (partition by manager) cnt
from dbtable
group by manager
Yields the following results:
MANAGER CNT
Domnic 1
John 1
If you drop the group by, you get:
MANAGER CNT
Domnic 2
Domnic 2
John 3
John 3
John 3
Are those the counts you're looking for? If so, then you can eliminate the duplicate rows with distinct:
select distinct manager, count(*) over (partition by manager) cnt
from dbtable
Which gives:
MANAGER CNT
John 3
Domnic 2

Related

Oracle Grouping Not Capturing All Rows

I have the following grouping query and it seems to be leaving out rows...
SELECT asscfirstname, assclastname, addeddate, COUNT(*)
FROM CLUD.masterassc
GROUP BY asscfirstname, assclastname, addeddate
having count (*) >1
order by count(*) desc;
This is my data:
asscfirstname | assclastname | addeddate
------------- ------------ ----------
john doe1 1/1/00
john doe1 1/1/00
john doe2 2/1/00
john doe2 2/1/00
john doe2 2/5/00
The query results only show john doe1. How do I get it to also include the john doe2 where the addeddate is 2/1/00 since there are two of those?
be sure you have nt hidden space try using trim()
SELECT trim(asscfirstname), trim(assclastname), trim(addeddate), COUNT(*)
FROM CLUD.masterassc
GROUP BY trim(asscfirstname), trim(assclastname), trim(addeddate)
having count (*) >1
order by count(*) desc;
A date in Oracle is actually a timestamp, but your default format doesn't show the time portion. Set the time to 00:00:00 before grouping:
SELECT asscfirstname, assclastname, trunc(addeddate), COUNT(*)
FROM CLUD.masterassc
GROUP BY asscfirstname, assclastname, trunc(addeddate)
having count (*) >1
order by count(*) desc;

SQL find and group consecutive number in rows without duplicate

So I have a table like this:
Taxi Client Time
Tom A 1
Tom A 2
Tom B 3
Tom A 4
Tom A 5
Tom A 6
Tom B 7
Tom B 8
Bob A 1
Bob A 2
Bob A 3
and the expected result will be like this:
Tom 3
Bob 1
I have used the partition function to count the consecutive value but the result become this:
Tom A 2
Tom A 3
Tom B 2
Bob A 2
Please help, I am not good in English, thanks!
This is a variation of a gaps-and-islands problem. You can solve it using window functions:
select taxi, count(*)
from (select t.taxi, t.client, count(*) as num_times
from (select t.*,
row_number() over (partition by taxi order by time) as seqnum,
row_number() over (partition by taxi, client order by time) as seqnum_c
from t
) t
group by t.taxi, t.client, (seqnum - seqnum_c)
having count(*) >= 2
)
group by taxi;
use distinct count
select taxi ,count( distinct cient)
from table_name
group by taxi
It seems your expected output is wrong
I don't see where you get the number 3 from. If you're trying to do what your question says and group by client in consecutive order only and then get the number of different groups, I can help you out with the following query. Bob has 1 group and Tom has 4.
Partition by taxi, ORDER BY taxi, time and check if this client matches the previous client for this taxi. If yes, do not count this row. If no, count this row, this is a new group.
SELECT FEE.taxi,
SUM(FEE.clientNotSameAsPreviousInSequence)
FROM
(
SELECT taxi,
CASE
WHEN PreviousClient IS NULL THEN
1
WHEN PreviousClient <> client THEN
1
ELSE
0
END AS clientNotSameAsPreviousInSequence
FROM
(
SELECT *,
LAG(client) OVER (PARTITION BY taxi ORDER BY taxi, time) AS PreviousClient
FROM table
) taxisWithPreviousClient
) FEE
GROUP BY FEE.taxi;

SQL - Distribution Count

Hi I have the following table:
crm_id | customer_id
jon 12345
jon 12346
ben 12347
sam 12348
I would like to show the following:
Crm_ID count | Number of customer_ids
1 2
2 1
Basically I want to count the number crm_ids that have 1,2,3,4,5+ customer_ids.
Thanks
One approach is to aggregate twice. First, aggregate over crm_id and generate counts. Then, aggregate over those counts themselves and generate a count of counts.
SELECT
cnt AS crm_id_cnt,
COUNT(*) AS num_customer_ids
FROM
(
SELECT crm_id, COUNT(DISTINCT customer_id) AS cnt
FROM yourTable
GROUP BY crm_id
) t
GROUP BY cnt;
Have a look at a demo below, given in MySQL as you did not specify a particular database (though my answer should run on most databases I think).
Demo

Count entries that have different values in other column

Here is an (simplified) example of DB I have (sorry for the ulgy format, I don't know how to write tables):
Name | Num
John | 1
John | 3
John | 4
Dany | 2
Andy | 5
Andy | 5
I want to count how many people have more at least two different Numbers.
For instance, here, only john, because he has 1, 3 and 4.
Not Andy because he has twice 2 and no other one.
And obviously not Dany because he has only one entry.
Thank you very much.
Try this.
select count(name) from table group by name having count(distinct num)>1
Try this:
SELECT A.Name, COUNT(DISTINCT A.Num) cnt
FROM tableA
GROUP BY A.Name
HAVING cnt >= 2;
select count(*)
from (
select Name from Temp group by Name having count(distinct num) > 1
) as a
Try this:
select name from `table` group by name,num having count(num)>1

Get top results for each group (in Oracle)

How would I be able to get N results for several groups in
an oracle query.
For example, given the following table:
|--------+------------+------------|
| emp_id | name | occupation |
|--------+------------+------------|
| 1 | John Smith | Accountant |
| 2 | Jane Doe | Engineer |
| 3 | Jack Black | Funnyman |
|--------+------------+------------|
There are many more rows with more occupations. I would like to get
three employees (lets say) from each occupation.
Is there a way to do this without using a subquery?
I don't have an oracle instance handy right now so I have not tested this:
select *
from (select emp_id, name, occupation,
rank() over ( partition by occupation order by emp_id) rank
from employee)
where rank <= 3
Here is a link on how rank works: http://www.psoug.org/reference/rank.html
This produces what you want, and it uses no vendor-specific SQL features like TOP N or RANK().
SELECT MAX(e.name) AS name, MAX(e.occupation) AS occupation
FROM emp e
LEFT OUTER JOIN emp e2
ON (e.occupation = e2.occupation AND e.emp_id <= e2.emp_id)
GROUP BY e.emp_id
HAVING COUNT(*) <= 3
ORDER BY occupation;
In this example it gives the three employees with the lowest emp_id values per occupation. You can change the attribute used in the inequality comparison, to make it give the top employees by name, or whatever.
Add RowNum to rank :
select * from
(select emp_id, name, occupation,rank() over ( partition by occupation order by emp_id,RowNum) rank
from employee)
where rank <= 3
tested this in SQL Server (and it uses subquery)
select emp_id, name, occupation
from employees t1
where emp_id IN (select top 3 emp_id from employees t2 where t2.occupation = t1.occupation)
just do an ORDER by in the subquery to suit your needs
I'm not sure this is very efficient, but maybe a starting place?
select *
from people p1
join people p2
on p1.occupation = p2.occupation
join people p3
on p1.occupation = p3.occupation
and p2.occupation = p3.occupation
where p1.emp_id != p2.emp_id
and p1.emp_id != p3.emp_id
This should give you rows that contain 3 distinct employees all in the same occupation. Unfortunately, it will give you ALL combinations of those.
Can anyone pare this down please?