Display the city name which has most number of branches - sql

I have tried to get city name which has most number of branches .
select C.City_name ,count(B.B_Name)
from tblcity C
inner join
tblBranch B
on c.city_id=B.City_id
group by C.City_name
order by count(B.B_Name) desc
Above code will give me the count of branches for particular city .
Please help me solve to get city name which has most number of branches

you can add TOP 1 to your query
select TOP 1 C.City_name ,count(B.B_Name)
from tblcity C
inner join
tblBranch B
on c.city_id=B.City_id
group by C.City_name
order by count(B.B_Name) desc

Use DENSE_RANK():
SELECT
City_Name, cnt
FROM
(
SELECT
c.City_name,
COUNT(b.B_Name) cnt,
DENSE_RANK() OVER (ORDER BY COUNT(b.B_Name) DESC) dr
FROM tblcity c
INNER JOIN tblBranch b
ON b.city_id = c.City_id
GROUP BY c.City_name
) t
WHERE dr = 1;
Using TOP 1 WITH TIES would be another option here, but that is specific to SQL Server.

Related

country with the highest number of tests(oracle plsql)

Data Model:
Hi, I am trying to get "country with the highest number of tests".
Query:
I tried using one table.. ok... but how I get it with "countryname"? How should I make this with inner join?
Join, as you said.
select s.countryname,
s.date_,
s.total_tests
from (select
row_number() over (order by a.total_tests desc) rn,
a.date_,
a.total_tests,
c.countryname
from cases_by_countries a join country c
on c.countryid = a.country_id
) s
where s.rn = 1;
if you need only the highest you should try this
select c.CountryID, ts.Total_Tests
from Country c
inner join (
select top(1) Country_ID, Total_Tests
from CASES_BY_COUNTRIES
order by Total_Tests desc
) ts on c.CountryID = ts.Country_ID

SQL Server: how to limit results based on query

I have a customer table, and a customer address table but I want to limit it by just one address. so even though a customer has two postal addresses I want to show only one for each customer. Forgive me if this is a silly question, I am new to programming
custid forename surname
---------------------------
1 Sam Supra
2 Kelly Kenwood
addid custid address addresstype
-------------------------------------------
1 1 Main street POSTAL
2 1 2nd Main street POSTAL
3 1 0712456254 Mobile
4 1 0526545686 LANDLINE
5 2 Second Street POSTAL
6 2 04756325654 Mobile
7 2 058654236545 LANDLINE
Query:
SELECT a.*
FROM dbo.customers a
LEFT OUTER JOIN dbo.addresses b ON a.custid = b.custid
WHERE b.addresstype = 'POSTAL'
You can use ROW_NUMBER():
SELECT c.*, a.*
FROM dbo.customers c LEFT JOIN
(SELECT a.*,
ROW_NUMBER() OVER (PARTITION BY a.custid ORDER BY a.addid DESC) as seqnum
FROM dbo.addresses a
WHERE a.addresstype = 'POSTAL'
) a
ON a.custid = c.custid AND seqnum = 1;
Notes:
Don't use arbitrary table aliases. Use abbreviations for the table names.
Presumably, you want to select the addresses, so I changed the SELECT clause.
This returns all customers, even those with no address. I am guessing that is your intention, although your query would return only customers with a postal address.
I assume you are interested in the last address entered:
SELECT
*
FROM
dbo.customers a
LEFT JOIN
dbo.addresses b on b.id =
(
SELECT
x.id
FROM
dbo.addresses x
WHERE
x.custid = a.custid
AND
x.addresstype = 'POSTAL'
ORDER BY
x.id DESC
)
SELECT c.*,
a.*
FROM dbo.customers c
LEFT JOIN (
SELECT a.*,
ROW_NUMBER() OVER (
PARTITION BY a.custid
ORDER BY a.addid DESC
) as seqnum
FROM dbo.addresses a
WHERE a.addresstype = 'POSTAL'
) a
ON a.custid = c.custid AND seqnum = 1;

How can I show the maximum score of each department with their names

I can select maximum the score of each department but I can't show the name of each person associated with the max score.
I tried to select the name and the maximum grade (with maximum function) but it doesn't work:
select max(stgrade)as highscore,StName,DepName --department
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on d.DepID=l.LessonID
inner join TBL_GRADES g on g.lessonid=l.LessonID
inner join TBL_STUDENT s on s.STID=g.stid
group by DepName,StName
order by DepName,highscore desc
You may try this...
select * from ( select rank() over (partition by DepName order by stgrade desc) as Slno, stgrade, stname, DepName
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on d.DepID=l.LessonID
inner join TBL_GRADES g on g.lessonid=l.LessonID
inner join TBL_STUDENT s on s.STID=g.stid ) as dep where dep.slno=1
First create rank() in decreasing order of grade for individual department. then select top record for same.
Note: Use RANK() or DENSE_RANK(), both will work fine for top 1 record, while if you want to select n highest grade then use DENSE_RANK(), at the last for slno pass n'th record you want to select.
Always hard to do theory selects, but while DarkRob's solution is good, it will remove students if for instance two people are best. This is why I love using cross apply:
select
d.Depname
, s.StName
, g.stgrade
from TBL_DEPARTMANTS d
inner join TBL_LESSONS l on
d.DepID=l.LessonID
inner join TBL_GRADES g on
g.lessonid=l.LessonID
inner join TBL_STUDENT s on
s.STID=g.stid
cross apply (
select
sub_d.DepID
, max(sub_g.stgrade) as maxgrade
from TBL_DEPARTMANTS sub_d
inner join TBL_LESSONS sub_l on
sub_d.DepID=sub_l.LessonID
inner join TBL_GRADES sub_g on
sub_g.lessonid=sub_l.LessonID
where sub_d.Dep_ID = d.Dep_ID
group by sub_d.DepID
) as sub
where g.stgrade = sub.maxgrade
This way you will get all the people with max grade per department and not just one.

How to apply HAVING to a column and not a function

I have two tables, one with the names of hacking students and another with the challenges they made. I need to return the id, names and the number of challenges of the hackers, e.g:
hacker_id name challenges_created
21283 Angela 6
88255 Patrick 5
5077 Rose 4
62743 Frank 4
96196 Lisa 1
But if more than one hacker created the same number of challenges and that number is less that of the hacker who made the most challenges, those hackers must be excluded from the results. In this case, the 4s must be excluded. I found the exact answer for the problem online, which looks like this (edited to use my table names):
SELECT c.hacker_id, h.name, COUNT(c.hacker_id) AS ctn
FROM Sample0.Hackers as h
LEFT JOIN Sample0.Challenges c ON h.hacker_id = c.hacker_id
GROUP BY h.hacker_id, h.name
HAVING ctn = (SELECT TOP 1 COUNT(c1.challenge_id) FROM Sample0.Challenges AS c1 GROUP BY c1.hacker_id ORDER BY COUNT(*)) OR
ctn NOT IN (SELECT COUNT(c2.challenge_id) FROM Sample0.Challenges AS c2 GROUP BY c2.hacker_id HAVING c2.hacker_id <> c.hacker_id);
I'm getting errors on the HAVING clause, saying "Invalid column name 'ctn'". I've only worked with HAVING once and can only use a basic function on it. I don't know why it's giving me this error.
I would handle this using analytic functions:
WITH cte AS (
SELECT c.hacker_id, h.name, COUNT(*) AS challenges_created,
RANK() OVER (ORDER BY COUNT(*) DESC) rnk,
COUNT(*) OVER (PARTITION BY COUNT(*)) cnt
FROM Sample0.Hackers as h
LEFT JOIN Sample0.Challenges c
ON h.hacker_id = c.hacker_id
GROUP BY h.hacker_id, h.name
)
SELECT
hacker_id,
name,
challenges_created
FROM cte
WHERE rnk = 1 OR cnt = 1;
The idea here is that an aggregate record should be retained if it either is tied for the highest challenge count or there are no other records having the same challenge count.
you can not use inline alias name try like below
SELECT
c.hacker_id,
h.name,
COUNT(c.hacker_id) AS ctn
FROM Sample0.Hackers as h
left JOIN Sample0.Challenges as c
ON h.hacker_id = c.hacker_id
GROUP BY c.hacker_id, h.name
HAVING COUNT(c.hacker_id) = (SELECT TOP 1 COUNT(c1.challenge_id) FROM Sample0.Challenges AS c1 GROUP BY c1.hacker_id ORDER BY COUNT(*)) OR
COUNT(c.hacker_id) NOT IN (SELECT COUNT(c2.challenge_id) FROM Sample0.Challenges AS c2 where c2.hacker_id <> c.hacker_id GROUP BY c2.hacker_id )
And your selection column and group by column was not from same table so it thrown error hacker_id' is invalid in the HAVING clause

How to sort by count with postgresql?

I have two tables:
Companies: (id, name, city)
Workers: (id, name)
I would like to get all companies and sort them by numbers of employes.
The result should give:
count | company id | company name | city
------------------------------------------
90 6 foo corp NY
45 9 bar corp LA
0 3 foobar corp HO
I tried:
select
c.*,
count(w.id) as c
from
companies c
left join
workers w
on
c.id = w.company_id
group by
c.id
order by
c desc;
But that's not working as it tells me to group by g.name too :/
Any ideas?
You've aliased the table and column as the same thing, so don't do that. It's not invalid, just tough to follow.
Anyway, include all columns that you're selecting that aren't aggregates in your group by:
select
count(w.id) as mycount,
w.company_id,
c.company_name,
c.city
from
companies c
left join workers w on
c.id=w.company_id
group by
w.company_id,
c.company_name,
c.city
order by mycount desc;
If you don't want the count result to be returned (because of an ORM framework or so), you could apply it directly in the order by clause:
select
c.*
from
companies c
left join
workers w
on
c.id = w.company_id
group by
c.id
order by
count(w.id) desc;
Tested with postgreSQL 11
Try this as a subquery:
SELECT C.*
FROM
(
SELECT C.Id, C.Company_Name, C.City, COUNT(W.Id) AS CNT
FROM Companies C
LEFT JOIN Workers W ON W.Company_Id = C.Id
GROUP BY C.Id, C.Company_Name, C.City
) T
ORDER BY T.CNT