How to get the max value for each group in Oracle? - sql

I've found some solutions for this problem, however, they don't seem to work with Oracle.
I got this:
I want a view to present only the informations about the oldest person for each team. So, my output should be something like this:
PERSON | TEAM | AGE
Sam | 1 | 23
Michael | 2 | 21
How can I do that in Oracle?

Here is an example without keep but with row_number():
with t0 as
(
select person, team, age,
row_number() over(partition by team order by age desc) as rn
from t
)
select person, team, age
from t0
where rn = 1;

select * from table
where (team, age) in (select team, max(age) from table group by team)

One method uses keep:
select team, max(age) as age,
max(person) keep (dense_rank first order by age desc) as person
from t
group by team;
There are other methods, but in my experience, keep works quite well.

select * from (select person,team,age,
dense_rank() over (partition by team order by age desc) rnk)
where rnk=1;

Using an Analytic Function returns all people with maximum age per team (needed if there are people with identical ages), selects Table one time only and is thus faster than other solutions that reference Table multiple times:
With MaxAge as (
Select T.*, Max (Age) Over (Partition by Team) MaxAge
From Table T
)
Select Person, Team, Age From MaxAge Where Age=MaxAge
;
This also works in MySQL/MariaDB.

Related

query to find the second most common word in a table (oracle sql)

So I have a table employees as shown below
ID | name | department
---|------|-----------
1 | john | home
2 | alex | home
3 | ryan | tech
I'm trying to group these by the department number and have the count displayed. But I am trying to select the second most common, which in this case it should return (tech 1). Any help on how to approach this is appreciated.
Edit:
By only using MINUS, I'm still not familiar with LIMIT when searching around online.
We can use COUNT along with DENSE_RANK:
WITH cte AS (
SELECT department, COUNT(*) AS cnt,
DENSE_RANK() OVER (ORDER BY COUNT(*) DESC) rnk
FROM yourTable
GROUP BY department
)
SELECT department, cnt
FROM cte
WHERE rnk = 2;
As of Oracle 12c, you might find the following limit query satisfactory:
SELECT department, COUNT(*) AS cnt
FROM yourTable
GROUP BY department
ORDER BY COUNT(*) DESC
OFFSET 1 ROWS FETCH NEXT 1 ROWS ONLY;
But this limit approach does not handle well the scenario where e.g. there might be 2 or more departments ties for first place. DENSE_RANK does a better job of handling such edge cases.

Largest number of job position of employees at a multiple Companies using SQL

I am trying to find out the most popular job position employees are working at a combination of companies. If there is a tie, however, then both are added to the table.
I have a file called employees_data.txt.
I have their name, company, job position, and age in that order.
Natali, Google, IT, 45
Nadia, Facebook, Sales, 25
Jacob, Google, IT, 32
Leonard, Bing, Custodian, 65
Kami, Amazon, Driver, 43
Paul, Facebook, Engineer, 31
Ashley, Walmart, IT, 34
Robert, Fedex, IT, 27
Rebecca, Ups, Driver, 29
Mal, Apple, Custodian, 73
Erin, Bing, Sales, 38
I know the expected outcome should be the IT position, I'm just unsure the sql command to read through and keep track of the positions.
Any help is greatly appreciated!
Feels like homework :laugh:
You need an aggregate (count, sum, min,max, etc,.) and a group by
select count(*), position
from t
group by position
https://www.db-fiddle.com/f/dUqdZaUGpHTAYv8vH1YhU1/0
to only return the 'top record' we can use a self join with row_number calculation like this... probably an easier and cleaner way to do it, but you get the idea.
SELECT count(*) as recordcount, t.position
FROM t
INNER JOIN (
SELECT *
,row_number() OVER (
ORDER BY recordCount DESC
) AS rn
FROM (
SELECT count(*) AS recordCount
,position
FROM t
GROUP BY position
) as a
) d ON t.position = d.position
AND d.rn = 1
group by t.position
https://www.db-fiddle.com/f/dUqdZaUGpHTAYv8vH1YhU1/1
You want aggregation with a window function. That is:
select p.*
from (select position, count(*) as cnt,
rank() over (order by count(*) desc) as seqnum
from t
group by position
) p
where seqnum = 1;
In the most recent version of Postgres, you don't even need a subquery because it now supports with ties:
select position, count(*) as cnt
from t
group by position
order by count(*) desc
fetch first 1 row with ties;
I suspect your assignment calls for a query something along these lines:
select job_position
from employees_data
group by job_position
order by count(*) desc
fetch first 1 row with ties
Assuming the table is call jobpositions, and the columns are as follows:
name, company, position,age
I would use:
select * from (
select position, COUNT(position) as countpos, ROW_NUMBER() OVER(ORDER BY count(position) DESC) as numpos
from jobpositions group by position order by count(position) desc
) tb1 where tb1.numpos=1
This seems to work in postgres, and i like it because it is simple.

Just another SQL case (GROUP BY)

I'm stuck on an SQL problem that I don't know how to solve.
Let's say I have a table like this (concerning estimations on house prices):
estimationID | estimationDate | userID | cityID
1 | '2020-01-01' | 123456 | 987654
2 | '2020-12-01' | 135790 | 975310
...
With estimationDate being the date when the estimation was made, userID the ID of the user who made the estimation and cityID the ID of the city where the estimation was made.
I need to get the maximum number of estimations made by one user (I don't care which one, I don't need an ID) for each city.
Something like
SELECT cityID,*maximum number of estimations made by one user from this city* FROM estimationsTable GROUP BY cityID
Any idea?
Step by step:
Get the number of estimations per user and city.
Get the maximum of these numbers per city.
The query:
select cityid, max(cnt)
from
(
select cityid, userid, count(*) as cnt
from estimationstable
group by cityid, userid
) counted
group by cityid
order by cityid;
try like below
with cte as (
select userid,cityid,count(*) as cnt
from table_name group by userid,cityid
)
, cte2 as (
select *,
row_number() over(partition by cityid order by cnt desc) rn
from cte
) select * from cte2 where rn=1
sol 1:
SELECT id, MAX(maximum_number_of_estimations)
FROM (SELECT id,COUNT(*) AS maximum_number_of_estimations
FROM TABLE x)group by id as final_query
sol2:
use order by Count DESC with group by`
something like this should work
the idea is you count all the occurrences in the inner query with the group by on your id and another query to get the max of it OR you use ORDER BY [Field] DESC
with GROUP BY which will automatically put the highest ones on the top
In BigQuery, I think you can do this without a subquery:
select distinct cityid,
(array_agg(userid order by count(*) desc, userid))[ordinal(1)] as userid,
max(count(*)) over (order by count(*) desc) as cnt
from estimationstable
group by cityid, userid

SQL query to select up to N records per criteria

I was wondering if it's possible to use SQL (preferably snowflake) to select up to N records given certain criteria.
To illustrate:
Lets say I have a table with 1 million records, containing full names and phone numbers.
There's no limits on the amount of phone numbers that can be assigned to X person, but I only want to select up to 10 numbers per person, even if the person has more than 10.
Notice I don't want to select just 10 records, I want the query to return every name in the table, I only want to ignore extra phone numbers when the person already has 10 of them.
Can this be done?
You can use window functions to solve this greatest-n-per-group problem:
select t.*
from (
select
t.*,
row_number() over(partition by name order by phone_number) rn
from mytable t
) t
where rn <= 10
Note that you need an ordering column to define what "top 10" actually means. I assumed phone_number, but you can change that to whatever suits your use case best.
Better yet: as commented by waldente, snowflake has the qualify syntax, which removes the need for a subquery:
select t.*
from mytable t
qualify row_number() over(partition by name order by phone_number) <= 10
This query will help your requirement:
select
full_name,
phonenumber
from
(select
full_name,
phonenumber,
ROW_NUMBER() over (partition by phonenumber order by full_name desc) as ROW_NUMBER from sample_tab) a
where
a.row_number between 1 and 10
order by
full_name asc,
phonenumber desc;
using Snowflake Qualify function:
select
full_name,
phonenumber
from
sample_tab qualify row_number() over (partition by phonenumber order by full_name) between 1 and 10
order by
full_name asc ,
phonenumber desc;

Get mixed in sql query

I've got a table in postgresql include in countries and bird species column. I want to get what country has the most number of bird species.How can I do that? any suggestion?
You can use dense_rank to get all the countries with the highest number of species.
select country from
(
select country, dense_rank() over(order by count(*) desc) as rnk
from yourtable
) t
where rnk = 1
A typical way to solve this is using group by and limit/fetch first 1 row only:
select country, count(*) as cnt
from t
group by country
order by count(*) desc
limit 1;
Note: in case multiple countries are tied, then this will only return one of them.