Return all rows with MAX value based on the calculation done on two columns - sql

I have a table named 'Houses' which contains fields 'house_id', 'house_type', 'bhk_detail', 'bed_count', 'furnishing_type', 'Beds_vacant'. Now i need to write a query to get the house details of the house having highest occupancy which bed_count - bed_vacant. I tried something like this:
SELECT hs.house_id, hs.house_type , hs.bhk_details, hs.bed_count , hs.furnishing_type, hs.Beds_vacant,
max(hs.bed_count - hs.Beds_vacant
FROM Houses as hs
GROUP BY hs.house_id, hs.house_type, hs.bhk_details, hs.bed_count, hs.furnishing_type, hs.Beds_vacant
HAVING MAX(hs.bed_count - hs.Beds_vacant)IN (SELECT max(hs.bed_count - hs.Beds_vacant) FROM Houses as hs)
The query worked for me but i was wondering if we can write it more precisely

I think the simplest way is top 1 with ties:
select top (1) with ties h.*
from Houses h
order by (h.bed_count - h.beds_vacant) desc;

Related

SQL query to return average of results using JOIN and GROUP BY

I have a simple manufacturing job card system that track parts and labor for an assigned job.
It consists of a JobHeader table that holds the Job Card number (JobHeader.JobNo), ID of the part being manufactured (JobHeader.RegNo) and quantity to be manufactured (JobHeader.RegNo).
There is a child table (JobLabour) that tracks all the times that have been worked on the job (JobLabour.WorkedTime)
I'm looking for a query that will return the average time taken to produce a part accross the last 5 job cards for that particular part.
The following query
SELECT TOP 5 JobHeader.RegNo, JobHeader.BOMQty, sum(JobLabour.WorkedTime) AS TotalTime FROM JobHeader INNER JOIN JobLabour ON JobHeader.JobNo=JobLabour.JobNo
WHERE JobHeader.RegNo='RM-BRU-0134'
GROUP BY JobHeader.BOMQty, JobHeader.JobNo, JobHeader.RegNo
will return this:
But what I'm looking for is a query that will return the average BOMQty and average totalTime. Something like this:
Is there a way to do this?
Your question explicitly mentions the "last five" but does not specify how that is determined. Presumably, you have some sort of date/time column in the data that defines this.
In SQL Server, you can use apply:
select jh.*, jl.*
from jobheader jh outer apply
(select top (5) avg(BOMQty) as avg_BOMQty, avg(totalTime) as avg_totalTime
from (select top (5) jl.*
from joblabour jl
where jl.regno = jh.regno
order by jl.<some datetime> -- however you determine the last five
) jl
) jl;
You can add a where clause to the outer query to filter on one or more particular jobs.
If I understand you correctly this will do the work
this will work for 1 RegNo='RM-BRU-0134' at a time
with topFive as (
SELECT TOP 5 JobHeader.RegNo, JobHeader.BOMQty, sum(JobLabour.WorkedTime) AS TotalTime
FROM JobHeader
INNER JOIN JobLabour ON JobHeader.JobNo = JobLabour.JobNo
WHERE JobHeader.RegNo = 'RM-BRU-0134'
GROUP BY JobHeader.BOMQty, JobHeader.JobNo, JobHeader.RegNo
)
select RegNo, avg(BOMQty) as BOMQty, avg(TotalTime) as TotalTime
from topFive
group by RegNo

How to make this 2 step query solution better

Query is made in MS Access :
I show now a simplified example of my problem.
I have one table Members
Name/age/nickname
- Tom/12/wolf
- Chris/11/ranger
- Phil/14/H-man
- Chris/16/walker
- Chris/18/Mo
Goal: How many times a name occurs , but only count when the nickname had an "a" in it.
I needed 2 queries;
Step1:
SELECT Members.Name, Members.Age, Members.Nickname
FROM Members
WHERE (((Members.Nickname) Like "*A*"));
Step2:
SELECT Step1.Name, Count(Step1.Age) AS AantalVanAge
FROM Step1
GROUP BY Step1.Name;
Result
- Chris 2
- Phil 1
You can achieve this in a single query using:
select t.name, count(*) as AantalVanAge
from members t
where t.nickname like "*A*"
group by t.name
Use your 1st query as a subquery in the 2nd step:
SELECT t.Name, Count(t.Age) AS AantalVanAge
FROM (
SELECT Name, Age
FROM Members
WHERE Nickname Like "*A*"
) AS t
GROUP BY t.Name;

mSSQL, SQL view, select, percentage query

So this is the requirement I need to meet:
Aggregated data of all the schools in the ESD, grouped by
SchoolDistrict.SchoolDistrictID
(get the same data as the school district scenario above, then add grouping by district, filtered to
EducationServiceDistrict. EducationServiceDistrictID
)
Also calculate percentage of pass, fail, and untested
How do I calculate the percentage pass, fail, and untested?
This is the query I have written so far.
CREATE VIEW district_map AS
SELECT * and SchoolDistrictID,
EducationServiceDistrict
FROM SchoolDistrict_View
and SchoolDistrict,
EducationServiceDistrict
GROUP BY EducationServiceDistrict.EducationServiceDistrictID
ORDER BYLeadWaterTestLocation.PassFail
This is the general idea of how these problems are solved - if you understand this simplified version you will be able to solve your problem.
select d.districtName,
s.studentCount,
case when s.studentCount=0 then 0 else s.passed / s.studentCount * 100 end as PassedPct
from district d
join (select districtId,
sum(studentCount) as studentCount,
sum(passed) as passed
from schools
group by districtId) as s
on d.districtId = s.districtId
order by d.districtName

Only a single result allowed for a SELECT that is part of an expression

I have the following SQL statement. It's throws the following error: "Only a single result allowed for a SELECT that is part of an expression". The goal of my sql statement is to get the name of the employee who made the 'cheapest' bribe.
The part between the brackets return the employee_id and the money it costs a day (of the relative cheapest bribe). These are two results while I only want the employee_id. So I just want to use the MIN part to get the right employee_id. How can I do this?
SELECT Voornaam, Achternaam
FROM Medewerker m JOIN
(
SELECT Medewerker_id
FROM Steekpenning
ORDER BY -1*Bedrag/(julianday(Begindatum) - julianday(Einddatum))
limit 1
) s
on m.Medewerker_id = s.Medewerker_id;
EDITED the answer. How can I expand this query to only show the bribes started this month? I think I need to use something like this? (julianday(Begindatum) - julianday('now')) > 31 but where?
Regards.
Cas
I think the following will work in SQLite:
select Firstname, Surname
from Employee e join
(select employee_id
from bribe
order by -1*Amount/(julianday(Startdate) - julianday(Enddate))
limit 1
) b
on e.employee_id = b.employee_id;

How to combine this query

In the query
cr is customers,
chh? ise customer_pays,
cari_kod is customer code,
cari_unvan1 is customer name
cha_tarihi is date of pay,
cha_meblag is pay amount
The purpose of query, the get the specisified list of customers and their last date for pay and amount of money...
Actually my manager needs more details but the query is very slow and that is why im using only 3 subquery.
The question is how to combine them ?
I have researched about Cte and "with clause" and "subquery in "where " but without luck.
Can anybody have a proposal.
Operating system is win2003 and sql server version is mssql 2005.
Regards
select cr.cari_kod,cr.cari_unvan1, cr.cari_temsilci_kodu,
(select top 1
chh1.cha_tarihi
from dbo.CARI_HESAP_HAREKETLERI chh1 where chh1.cha_kod=cr.cari_kod order by chh1.cha_RECno) as sontar,
(select top 1
chh2.cha_meblag
from dbo.CARI_HESAP_HAREKETLERI chh2 where chh2.cha_kod=cr.cari_kod order by chh2.cha_RECno) as sontutar
from dbo.CARI_HESAPLAR cr
where (select top 1
chh3.cha_tarihi
from dbo.CARI_HESAP_HAREKETLERI chh3 where chh3.cha_kod=cr.cari_kod order by chh3.cha_RECno) >'20130314'
and
cr.cari_bolge_kodu='322'
or
cr.cari_bolge_kodu='324'
order by cr.cari_kod
You will probably speed up the query by changing your last where clause to:
where (select top 1 chh3.cha_tarihi
from dbo.CARI_HESAP_HAREKETLERI chh3 where chh3.cha_kod=cr.cari_kod
order by chh3.cha_RECno
) >'20130314' and
cr.cari_bolge_kodu in ('322', '324')
order by cr.cari_kod
Assuming that you want both the date condition met and one of the two codes. Your original logic is the (date and code = 322) OR (code = 324).
The overall query can be improved by finding the record in the chh table and then just using that. For this, you want to use the window function row_number(). I think this is the query that you want:
select cari_kod, cari_unvan1, cari_temsilci_kodu,
cha_tarihi, cha_meblag
from (select cr.*, chh.*,
ROW_NUMBER() over (partition by chh.cha_kod order by chh.cha_recno) as seqnum
from dbo.CARI_HESAPLAR cr join
dbo.CARI_HESAP_HAREKETLERI chh
on chh.cha_kod=cr.cari_kod
where cr.cari_bolge_kodu in ('322', '324')
) t
where chh3.cha_tarihi > '20130314' and seqnum = 1
order by cr.cari_kod;
This version assumes the revised logic date/code logic.
The inner subquery select might generate an error if there are two columns with the same name in both tables. If so, then just list the columns instead of using *.