what I'm trying to do is to only display only rows with a count value greater than 3.
select pharm_name, count(1) as "Number of Staff"
from pharmacies p, pharmacy_staff_store pss
where p.pharm_id = pss.pharmacy_id
group by pharm_name;
For example this query might return me 5 rows where under the "Number of Staff" it'll say for instance 5,4,3,2,1 but I only want it to return me those rows where the count is 3 and above. Is there a feasible way to do this?
use the having :
select pharm_name, count(1) as "Number of Staff"
from pharmacies p, pharmacy_staff_store pss
where p.pharm_id = pss.pharmacy_id
group by pharm_name
having count(1) > 3
or you can write in this way:
select * from (
select pharm_name, count(1) as x
from pharmacies p, pharmacy_staff_store pss
where p.pharm_id = pss.pharmacy_id
group by pharm_name)
where x>3
First dont use WHERE join
Promote the use of explict JOIN sintaxis, Aaron Bertrand wrote a nice article Bad habits to kick : using old-style JOINs about it.
Then use HAVING to filter from the result.
SELECT pharm_name,
Count(1) AS "Number of Staff"
FROM pharmacies p
JOIN pharmacy_staff_store pss
ON p.pharm_id = pss.pharmacy_id
GROUP BY pharm_name
HAVING COUNT(1) > 3;
Also I wouldnt use COUNT(1) if someone change the order of the fields on db your query wouldnt notice and will show wrong behavior. Use Count(fieldname)
Related
SELECT artist.name, recording.name, MAX(recording.length)
FROM recording
INNER JOIN (artist_credit
INNER JOIN (artist_credit_name
INNER JOIN artist
ON artist_credit_name.artist_credit=artist.id)
ON artist_credit_name.artist_credit=artist_credit.id)
ON recording.artist_credit=artist_credit.id
WHERE artist.gender=1
AND recording.length <= (SELECT MAX(recording.length) FROM recording)
GROUP BY artist.name, recording.name
ORDER BY artist.name
We are using the MusicBrainz database for school and we are having troubles with the "GROUP BY" because we have two columns (it works with one column, but not two). We want the result to display just one artist with his second longest recording time, but the code displays all the recording time of every song of the same artist.
Any suggestions? Thanks.
You don't need to do multiple joins looking closely at the join conditions. They can be reduce to just one join as shown below.
SELECT DISTINCT B.name, A.name, A.length
FROM recording A JOIN artist B
ON A.artist_credit=B.id
WHERE B.gender=1
AND A.length=(SELECT C.length FROM recording C
WHERE C.artist_credit=B.artist_credit
ORDER BY C.length LIMIT 1, 1)
ORDER BY B.name;
See Using MySQL LIMIT to get the nth highest value
As others have pointed out, the join statement can be reduced. Also there seems to be a problem with the operator in the AND statement; it should be < and not <= in order to get the second highest length (Se here: What is the simplest SQL Query to find the second largest value?).
I would suggest trying out the following:
SELECT artist.name, recording.name, MAX(recording.length)
FROM recording
JOIN artist ON recording.artist_credit = artist.id
WHERE
artist.gender=1
AND
recording.length < (SELECT MAX(recording.length) FROM recording)
GROUP BY artist.name
ORDER BY artist.name
I have an SQL sentence :
SELECT application.id,title,url,company.name AS company_name,package_name,ranking,date,platform,country.name AS country_name,collection.name AS collection_name,category.name AS category_name FROM application
JOIN application_history ON application_history.application_id = application.id
JOIN company ON application.company_id = company.id
JOIN country ON application_history.country_id = country.id
JOIN collection ON application_history.collection_id = collection.id
JOIN category ON application_history.category_id = category.id
WHERE application.platform=0
AND country.name ='CZ'
AND collection.name='topfreeapplications'
AND category.name='UTILITIES'
AND application_history.ranking <= 10
AND date::date BETWEEN date (CURRENT_DATE - INTERVAL '1 month') AND CURRENT_DATE
ORDER BY application_history.ranking ASC
It produces this result :
I'd like to add both a column average ranking for a given package, and a column number of appearances, which would count the number a package appears in the list. I'd also like to Group results by package_name, so that I don't have redundancies.
So far, I've tried to add a GROUP BY By clause before the ORDER BY :
GROUP BY package_name
But it returns me an error :
column "application.id" must appear in the GROUP BY clause or be used in an aggregate function
If I add each and every column it asks me for, it doesn't work.
I have also tried to count the number of package names, by adding after the SELECT :
COUNT(package_name) AS count
It produces a similar error.
How could I get the result I'm looking for ? Should I make two queries instead, or is it possible to get everything at once ?
I precise I have looked at other answers on S.O, but none of them tries to make the COUNT on a "produced" column.
Thank you for your help.
Edit :
Here is the result I expected at first :
Although Gordon's advice didn't give me the proper result it put me on the good track, when I read this :
From the docs : "Unlike regular aggregate functions, use of a window function does not cause rows to become grouped into a single output row."
So I came back to using COUNT and AVG alone. My problem was that I wanted to display the ranking column and date to check whether things were right. But putting these column into the Select prevented the GROUP BY to work as expected, as mentioned by Jarlh in the comments.
The working query :
SELECT application.id,title,url,company.name AS company_name,package_name,platform,country.name AS country_name,collection.name AS collection_name,category.name AS category_name,
COUNT(package_name) AS count, AVG(application_history.ranking) AS avg
FROM application
JOIN application_history ON application_history.application_id = application.id
JOIN company ON application.company_id = company.id
JOIN country ON application_history.country_id = country.id
JOIN collection ON application_history.collection_id = collection.id
JOIN category ON application_history.category_id = category.id
WHERE application.platform=0
AND country.name ='CZ'
AND collection.name='topfreeapplications'
AND category.name='UTILITIES'
AND application_history.ranking <= 10
AND date::date BETWEEN date (CURRENT_DATE - INTERVAL '1 month') AND CURRENT_DATE
GROUP BY package_name,application.id,company.name,country.name,collection.name,category.name
ORDER BY count DESC
I think you want window/analytic functions. The following adds two columns, one for the count of rows for each package and the other an average ranking for them:
SELECT application.id, title, url, company.name AS company_name, package_name,
ranking, date, platform, country.name AS country_name,
collection.name AS collection_name, category.name AS category_name,
count(*) over (partition by package_name) as count,
avg(ranking) over (partition by package_name) as avg_package_ranking
FROM application . . .
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 *.
The query I'm running in DB2
select yrb_customer.name,
yrb_customer.city,
CASE count(*) WHEN 0 THEN 0 ELSE count(*) END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid and yrb_member.club like '%Club%'
group by yrb_customer.name, yrb_customer.city order by count(*)
Shows me people which are part of clubs which has the word 'Club' in it, and it shows how many such clubs they are part of (#UniClubs) along with their name and City. However for students who are not part of such a club, I would still like for them to show up but just have 0 instead of them being hidden which is what's happening right now. I cannot get this functionality with count(*). Can somebody shed some light? I can explain further if the above is not clear enough.
I'm not familiar with DB2 so I'm taking a stab in the dark, but try this:
select yrb_customer.name,
yrb_customer.city,
CASE WHEN yrb_member.club like '%Club% THEN count(*) ELSE 0 END as #UniClubs
from yrb_member, yrb_customer
where yrb_member.cid = yrb_customer.cid
group by yrb_customer.name, yrb_customer.city order by count(*)
Basically you don't want to filter for %Club% in your WHERE clause because you want ALL rows to come back.
You're going to want a LEFT JOIN:
SELECT yrb_customer.name, yrb_customer.city,
COUNT(yrb_member.club) as clubCount
FROM yrb_customer
LEFT JOIN yrb_member
ON yrb_member.cid = yrb_customer.cid
AND yrb_member.club LIKE '%Club%
GROUP BY yrb_customer.name, yrb_customer.city
ORDER BY clubCount
Also, if the tuple (yrb_customer.name, yrb_customer.city) is unique (or is supposed to be - are you counting all students with the same name as the same person?), you might get better performance out of the following:
SELECT yrb_customer.name, yrb_customer.city,
COALESCE(club.count, 0)
FROM yrb_customer
LEFT JOIN (SELECT cid, COUNT(*) as count
FROM yrb_member
WHERE club LIKE '%Club%
GROUP BY cid) club
ON club.cid = yrb_customer.cid
ORDER BY club.count
The reason that your original results were being hidden was because in your original query, you have an implicit inner join, which of course requires matching rows. The implicit-join syntax (comma-separated FROM clause) is great for inner (regular) joins, but is terrible for left-joins, which is what you really needed. The use of the implicit-join syntax (and certain types of related filtering in the WHERE clause) is considered deprecated.
I am trying to make a query of
"What are the names of the producers
with at least 2 properties with areas
with less than 10"
I have made the following query that seems to work:
select Producers.name
from Producers
where (
select count(Properties.prop_id)
from Properties
where Properties.area < 10 and Properties.owner = Properties.nif
) >= 2;
yet, my lecturer was not very happy about it. He even thought (at least gave me the impression of) that this kind of queries wouldn't be valid in oracle.
How should one make this query, then? (I have at the moment no way of getting to speak with him btw).
Here are the tables:
Producer (nif (pk), name, ...)
Property (area, owner (fk to
producer), area, ... )
The having clause is typically used to filter on aggregate data (like counts, sums, max, etc).
select
producers.name,
count(*)
from
producers,
property
where
producers.nif = property.owner and
property.area < 10
group by
producers.name
having
count(*) >= 2
select P.name
from Producers p, Properties pr
where p.nif = pr.Owner
AND Properties.area < 10
GROUP BY Producers.name
having Count(*) >= 2