How to use select MIN() in SQL when one field can not be grouped? - sql

I am quite new to SQL so please be gentle. I have tried search for an answer but can not find anything.
I have the following data in a table
Code Area Department Level Name
HWNET Highways Network Services 2 Bob Jones
HWNET Highways Network Services 1 Jim Smith
HWTRA Highways Traffic Services 2 Andy Johnson
HWTRA Highways Traffic Services 1 David Turner
I want to select all the columns from the table but only for the minimum value for each level. My problem is that I need to know the Name but this is stopping me from using the group by function
If I use this it brings back every row in the table
SELECT Code, Area, Department,MIN(Level) Level , Name
FROM TABLE_NAME
GROUP BY Code, Area,Department, Name
This brings back the correct rows but does not contain the Name.
SELECT Code, Area, Department,MIN(Level) Level
FROM TABLE_NAME
GROUP BY Code, Area,Department
Is there a way for me bring back this set of results?
Code Area Department Level Name
HWNET Highways Network Services 1 Jim Smith
HWTRA Highways Traffic Services 1 David Turner
Thanks is advance

select t.*
from TABLE_NAME t
inner join
(
SELECT Code, Area, Department,MIN(Level) mLevel
FROM TABLE_NAME
GROUP BY Code, Area,Department
) x on x.Code = t.code
and x.Area = t.area
and x.Department = t.Department
and x.mLevel = t.level

Usually I do it in this ways:
select *
from TABLE_NAME
where (Department,
Level) in (select Department,
min(Level)
from TABLE_NAME
group by Department)
Here a demo in SQL Fiddle.
Based on your data I used only Department and Level, but if you need to use also Code and Area to identify the right rows just ass them in the WHERE clause and in the SELECT of the subquery.
select *
from TABLE_NAME
where (Code,
Area
Department,
Level) in (select Code,
Area,
Department,
min(Level)
from TABLE_NAME
group by Code,
Area,
Department)

You could try something like
SELECT Code, Area, Department, Level, Name
FROM (
SELECT Code, Area, Department, Level, Name, ROW_NUMBER() OVER (PARTITION BY Code, Area, Department, Name ORDER BY Level) __RN
FROM TABLE_NAME) subQuery
WHERE __RN = 1
Without knowing more about the schema of the table, it's not easy to say what would be the best way of joining from a grouped version of your data to the table. Using ROW_NUMBER() is likely to be far more efficient, but you might be able to reduce the elements in your partition depending on what is actually the unique key in your table.

select
s.*
from table s,
(select
code, area, department, min(level) m
from
table
group by
code,area,department
) min_v
where
s.code = min_v.code
and s.area= min_v.area
and s.department = min_v.department
and s.level = min_v.m
;

Related

SQL - finding the minimal value of a specific group and giving extended information about it

I would like to introduce myself as someone who has just recently started to fiddle a bit with SQL. Throughout my learning process I have come across a very specific problem and thus, my question is very specific too. Given the following table:
How should my list of commands look in order to get this following table:
In other words, what should I write to basically show the minimal salary and the id of its owner for each country. I have tried using GROUP BY but all I could get is the minimal salary per country whereas my goal was to show the id that belongs to the minimal salary too.
Hope I got my question clear and I thank everyone for the support.
This is a typical greatest-n-per-group problem.
One cross-database solution is to filter with a subquery:
select t.*
from mytable t
where t.salary = (select min(t1.salary) from mytable t1 where t1.country = t.country)
For performance with this query, you want an index on (country, salary).
You can also use window functions, if your database supports that:
select id, country, salary
from (
select t.*, rank() over(partition by country order by salary) rn
from mytable t
) t
where rn = 1
You can do by
select
id,
country,
salary
from
(
select
id,
country,
salary,
row_number() over (partition by country order by salary) as rnk
from table
)val
where rnk = 1

Oracle group by functions

I have a table with the following values.
read_count users manager
----------------------------------
16 Ann Jake
12 Ann Jake
19 Tom Martin
I am trying to group the values based on the manager and take the sum of maximum read_count per user.
something like
select manager,sum(max(read_count)) from table group by manager
(I know this group by doesn't work. Just gave here for better understanding)!
Here is one approach. Use row_number() to enumerate the rows for each user/manager combination in descending order by read_count. Then, use condition sum to get only the one value per user:
select manager,
sum(case when seqnum = 1 then read_count end) as SumMaxReadCountPerUser
from (select t.*,
row_number() over (partition by manager, users order by read_count desc
) as seqnum
from table t
) t
group by manager;
You can also do this with nested group by statements:
select manager, sum(max_read_count)
from (select manager, users, max(read_count) as max_read_count
from table t
group by manager, users
) mu
group by manager;
I prefer the first method because it generalizes more easily, say if you want the sum of the two highest values.

Select entry of each group having exactly 1 entry

I am looking for an optimized query
let me show you a small example.
Lets suppose I have a table having three field studentId, teacherId and subject as
Now I want those data in which a physics teacher is teaching to only one student, i.e
teacher 300 is only teaching student 3 and so on.
What I have tried till now
select sid,tid from tabletesting with(nolock)
where tid in (select tid from tabletesting with(nolock)
where subject='physics' group by tid having count(tid) = 1)
and subject='physics'
The above query is working fine. But I want different solution in which I don't have to scan the same table twice.
I also tried using Rank() and Row_Number() but no result.
FYI :
I have showed you an example, this is not the actual table i am playing with, my table contain huge number of rows and columns and where clause is also very complex(i.e date comparison etc.), so I don't want to give the same where clause in subquery and outquery.
You can do this with window functions. Assuming that there are no duplicate students for a given teacher (as in your sample data):
select tt.sid, tt.tid
from (select tt.*, count(*) over (partition by teacher) as scnt
from TableTesting tt
) tt
where scnt = 1;
Another way to approach this, which might be more efficient, is to use an exists clause:
select tt.sid, tt.tid
from TableTesting tt
where not exists (select 1 from TableTesting tt1 where tt1.tid = tt.tid and tt1.sid <> tt.sid)
Another option is to use an analytic function:
select sid, tid, subject from
(
select sid, tid, subject, count(sid) over (partition by subject, tid) cnt
from tabletesting
) X
where cnt = 1

Using Aggregate Functions in sql

Hoe can I do following thing without using a VIEW from one Query.
!--CREATE THE VIEW
CREATE OR REPLACE VIEW BDGTMGR
AS
SELECT MANAGERID,SUM(BUDGET) AS BDGT FROM
N_DEPT GROUP BY MANAGERID ;
!-- THEN GET RESULT FROM THE VIEW
SELECT MANAGERID FROM BDGTMGR WHERE BDGT = (select MAX(BDGT) FROM BDGTMGR);
Here N_DEPT is may original Table which has columns named DID, MANAGERID and BUDGET.
I want to get MANAGERID who controls Maximum Budget. A Manager can control more than one Department. DID is the primary key for this table.
How can I do this?
select MANAGERID,SUM(BDGT)
from N_DEPT
group by MANAGERID
order by SUM(BDGT) desc limit 1
You can do it like this:
SELECT aux.MANAGERID
FROM
(SELECT MANAGERID,
SUM(BUDGET) AS BDGT
FROM N_DEPT
GROUP BY MANAGERID) aux
INNER JOIN BDGTMGR b ON b.MANAGERID = aux.MANAGERID
WHERE b.BDGT = (select MAX(BDGT) FROM BDGTMGR);
The following query will work (modify depending on your flavour of SQL):
SELECT TOP 1 MANAGERID FROM N_DEPT GROUP BY MANAGERID ORDER BY SUM(BUDGET) DESC

How to find the highest populated instance in a column in SQL

So I have a table (person), that contains columns such as persons name, age, eye-color, favorite movie.
How do I find the most popular eye color(s), returning just the eye color (not the count) using SQL (Microsft Access), without using top as there might be multiple colours with the same count.
Thank you
SELECT
EyeColor
FROM
Person
GROUP BY
EyeColor
HAVING
COUNT(*) = (
SELECT MAX(i.EyeColorCount) FROM (
SELECT COUNT(*) AS EyeColorCount FROM Person GROUP BY EyeColor
) AS i
)
In Access, I think you need something on the lines of:
SELECT First(t.Eyecolor) AS FirstOfEyeColor
FROM (SELECT p.EyeColor, Count(p.EyeColor) AS C
FROM Person p
GROUP BY p.EyeColor
ORDER BY Count(p.EyeColor) DESC) AS t;