SQL - Counting only one table's entries in joint query - sql

This seems like a regular thing to do, but I can't seem to find how to do it.
I have a join query
SELECT a.nom_batim, COUNT(b.maxten) AS NumFaulty
FROM tblTrials AS b, tblRooms AS a
WHERE b.batiment = a.batiment
AND b.maxten > 10
GROUP BY a.nom_batim
ORDER BY a.nom_batim
that should only return a count of the tblTrials entries. However, since I don't know how to code that, it's currently counting all occurances of b.maxten > 10, TIMES all occurances of b.batiment = a.batiment. I have 1 actual occurance of b.maxten > 10 in the table, but 231 occurances of b.batiment = a.batiment (the tables are set up badly, not my choice; these tables are considered read-only to me), so it returns a count of 231.
How do I COUNT(b.maxten) correctly, but still display a.nom_batim as a user-friendly representation of the batiment ID field? (a.nom_batim is the long name for the building #batiment)
UPDATE
This is what I ended up doing so far..
SELECT a.nom_batim, COUNT(b.batiment) AS NumFaulty
FROM (SELECT DISTINCT nom_batim, batiment FROM tblRooms) AS a
INNER JOIN tblTrials AS b ON a.batiment = b.batiment
WHERE b.maxten > 10
GROUP BY a.nom_batim
ORDER BY a.nom_batim
It works but seems like a resource hog when I only need max ~30 values from tblRooms, but have to query all 5000+ rows selecting only distinct batiment values. Is there no way to do this without having a batiment table tblBatiment: batiment, nom_batim I know it's the best way but I don't have the access.

You can perform the count in a sub-query so it only applies to the one table's records:
SELECT ..
FROM (SELECT batiment, COUNT(maxten) FROM tblTrials WHERE maxten > 10) AS b
,tblRooms AS a
...
Otherwise, the count is applying across all records in the final result, because the query engine doesn't differentiate between records coming from one place or another in a COUNT.

Going back to your original query, you can get what you want if you have an identity column on the tblTrials table:
SELECT a.nom_batim, COUNT(distinct b.id) AS NumFaulty
FROM tblTrials b INNER JOIN tblRooms a
ON b.batiment = a.batiment
WHERE b.maxten > 10
GROUP BY a.nom_batim
ORDER BY a.nom_batim
I also replaced your join syntax with the correct join syntax (using the "join" keyword).

Try this:
SELECT a.nom_batim, COUNT(b.maxten) AS NumFaulty
FROM tblTrials AS b, tblRooms AS a
WHERE b.batiment = a.batiment
GROUP BY a.nom_batim
HAVING count(b.maxten) > 10
ORDER BY a.nom_batim

The best I could do so far which works:
SELECT a.nom_batim AS Building, Count(q.batiment) AS Fixes
FROM (SELECT DISTINCT nom_batim, batiment FROM tblRooms) AS a
INNER JOIN tblTrials AS q
ON a.batiment = q.batiment
WHERE q.maxten > 10
GROUP BY a.nom_batim
Seems like the SELECT DISTINCT nom_batim, batiment FROM tblRooms would be slow considering tblTrials may contain 60k entries and tblRooms may contain 10k entries.. but the entries aren't input yet so I can't really test it. Gordon made a good point that if it's returning the same stuff, it's likely ~the same speed. I do have multi-field primary keys so it might help things along as well (not as much as an ID field perhaps but what can you do).
Thanks to others that answered.

Try to use:
HAVING b.maxten>10

Related

how to get count of a column along with column from another table

is there any other way for this problem .I wanted to use group by cant use ii.
my solution:
SQL> select (select count(dr_id)
from cus_detail c
where c.dr_id=d.dr_id) as count_cus,dr_name from driver_detail d;
COUNT_CUS DR_NAME
---------- ---------------
1 raju
0 mandi
2 sajuman
3 babu ram coi
0 daju
0 bare babu
use this one.
select count(c.dr_id) as count_cus, d.dr_name
from driver_detail d
inner join cus_detail c on c.dr_id=d.dr_id
group by d.dr_name
I'm not totally sure I understand what you're asking but I think you're asking how to group things and bring in data from another table
I typically prefer to do this as a grouping subquery:
select
d.dr_name,
c.ctr
from
(select dr_id, count(dr_id) ctr from cus_detail group by dr_id) c
INNER JOIN driver_detail d ON c.dr_id=d.dr_id
The reason why here is that by grouping on the id when counting means we can keep a count for two different people (i.e. different id) both called John. If instead we joined on id then grouped on the Name then two different people both called John would have their counts added together
It's also good to group and count in a subquery because sometimes grouping and counting in the outer query introduces wrong counts if three or more tables are related in 1:Many fashion. If a record in a had 3 records in b and 4 records in c, and we join all before we count we will count 12 records. If we group first we will be joining in 1:1 relationship instead and the counter won't inflate erroneously
If two DR_NAME are same then GROUP BY can give different result then what your current query will give.
So better to use an analytical function as the following:
SELECT
COUNT(C.DR_ID) OVER(
PARTITION BY C.DR_ID
) AS COUNT_CUS,
DR_NAME
FROM
DRIVER_DETAIL D
JOIN CUS_DETAIL C ON ( C.DR_ID = D.DR_ID )
Cheers!!
I think you want a basic aggregation query. Your method is correct (although it could be formatted better). The more standard method is join/group by:
select d.dr_name, count(c.dr_id)
from driver_detail d left join
cus_detail c
on c.dr_id = d.dr_id
group by d.dr_name;

COUNT is outputting more than one row

I am having a problem with my SQL query using the count function.
When I don't have an inner join, it counts 55 rows. When I add the inner join into my query, it adds a lot to it. It suddenly became 102 rows.
Here is my SQL Query:
SELECT COUNT([fmsStage].[dbo].[File].[FILENUMBER])
FROM [fmsStage].[dbo].[File]
INNER JOIN [fmsStage].[dbo].[Container]
ON [fmsStage].[dbo].[File].[FILENUMBER] = [fmsStage].[dbo].[Container].[FILENUMBER]
WHERE [fmsStage].[dbo].[File].[RELATIONCODE] = 'SHIP02'
AND [fmsStage].[dbo].[Container].DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08'
GROUP BY [fmsStage].[dbo].[File].[FILENUMBER]
Also, I have to do TOP 1 at the SELECT statement because it returns 51 rows with random numbers inside of them. (They are probably not random, but I can't figure out what they are.)
What do I have to do to make it just count the rows from [fmsStage].[dbo].[file].[FILENUMBER]?
First, your query would be much clearer like this:
SELECT COUNT(f.[FILENUMBER])
FROM [fmsStage].[dbo].[File] f INNER JOIN
[fmsStage].[dbo].[Container] c
ON v.[FILENUMBER] = c.[FILENUMBER]
WHERE f.[RELATIONCODE] = 'SHIP02' AND
c.DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08';
No GROUP BY is necessary. Otherwise you'll just one row per file number, which doesn't seem as useful as the overall count.
Note: You might want COUNT(DISTINCT f.[FILENUMBER]). Your question doesn't provide enough information to make a judgement.
Just remove GROUP BY Clause
SELECT COUNT([fmsStage].[dbo].[File].[FILENUMBER])
FROM [fmsStage].[dbo].[File]
INNER JOIN [fmsStage].[dbo].[Container]
ON [fmsStage].[dbo].[File].[FILENUMBER] = [fmsStage].[dbo].[Container].[FILENUMBER]
WHERE [fmsStage].[dbo].[File].[RELATIONCODE] = 'SHIP02'
AND [fmsStage].[dbo].[Container].DELIVERYDATE BETWEEN '2016-10-06' AND '2016-10-08'

Count of how many times id occurs in table SQL regexp

Hi I have a redshift table of articles that has a field on it that can contain many accounts. So there is a one to many relationship between articles to accounts.
However I want to create a new view where it lists the partner id's in one column and in another column a count of how many times the partner id appears in the articles table.
I've attempted to do this using regex and created a new redshift view, but am getting weird results where it doesn't always build properly. So one day it will say a partner appears 15 times, then the next 17, then the next 15, when the partner id count hasn't actually changed.
Any help would be greatly appreciated.
SELECT partner_id,
COUNT(DISTINCT id)
FROM (SELECT id,
partner_ids,
SPLIT_PART(partner_ids,',',i) partner_id
FROM positron_articles a
LEFT JOIN util.seq_0_to_500 s
ON s.i < regexp_count (partner_ids,',') + 2
OR s.i = 1
WHERE i > 0
AND regexp_count (partner_ids,',') = 0
ORDER BY id)
GROUP BY 1;
Let's start with some of the more obvious things and see if we can start to glean other information.
Next GROUP BY 1 on your outer query needs to be GROUP BY partner_id.
Next you don't need an order by in your INNER query and the database engine will probably do a better job optimizing performance without it so remove ORDER BY id.
If you want your final results to be ordered then add an ORDER BY partner_id or similar clause after your group by of your OUTER query.
It looks like there are also problems with how you are splitting a partnerid from partnerids but I am not positive about that because I need to understand your view and the data it provides to know how that affects your record count for partnerid.
Next your LEFT JOIN statement on the util.seq_0_to_500 I am pretty sure you can drop off the s.i = 1 as the first condition will satisfy that as well because 2 is greater than 1. However your left join really acts more like an inner join because you then exclude any non matches from positron_articles that don't have a s.i > 0.
Oddly then your entire join and inner query gets kind of discarded because you only want articles that have no commas in their partnerids: regexp_count (partner_ids,',') = 0
I would suggest posting the code for your util.seq_0_to_500 and if you have a partner table let use know about that as well because you can probably get your answer a lot easier with that additional table depending on how regexp_count works. I suspect regex_count(partnerids,partnerid) exampleregex_count('12345,678',1234) will return greater than 0 at which point you have no choice but to split the delimited strings into another table before counting or building a new matching function.
If regex_count only matches exact between commas and you have a partner table your query could be as easy as this:
SELECT
p.partner_id
,COUNT(a.id) AS ArticlesAppearedIn
FROM
positron_articles a
LEFT JOIN PARTNERTABLE p
ON regexp_count(a.partnerids,p.partnerid) > 0
GROUP BY
p.partner_id
I will actually correct myself as I just thought of a way to join a partner table without regexp_count. So if you have a partner table this might work for you. If not you will need to split strings. It basically tests to see if the partnerid is the entire partnerids, at the beginning, in the middle, or at the end of partnerids. If one of those is met then the records is returned.
SELECT
p.partner_id
,COUNT(a.id) AS ArticlesAppearedIn
FROM
PARTNERTABLE p
INNER JOIN positron_articles a
ON
(
CASE
WHEN a.partnerids = CAST(p.partnerid AS VARCHAR(100)) THEN 1
WHEN a.partnerids LIKE p.partnerid + ',%' THEN 1
WHEN a.partnerids LIKE '%,' + p.partnerid + ',%' THEN 1
WHEN a.partnerids LIKE '%,' + p.partnerid THEN 1
ELSE 0
END
) = 1
GROUP BY
p.partner_id

SQL "Count (Distinct...)" returns 1 less than actual data shows?

I have some data that doesn't appear to be counting correctly. When I look at the raw data I see 5 distinct values in a given column, but when I run an "Count (Distinct ColA)" it reports 4. This is true for all of the categories I am grouping by, too, not just one. E.g. a 2nd value in the column reports 2 when there are 3, a 3rd value reports 1 when there are 2, etc.
Table A: ID, Type
Table B: ID_FK, WorkID, Date
Here is my query that summarizes:
SELECT COUNT (DISTINCT B.ID_FK), A.Type
FROM A INNER JOIN B ON B.ID_FK = A.ID
WHERE Date > 5/1/2013 and Date < 5/2/2013
GROUP BY Type
ORDER BY Type
And a snippet of the results:
4|Business
2|Design
2|Developer
Here is a sample of my data, non-summarized. Pipe is the separator; I just removed the 'COUNT...' and 'GROUP BY...' parts of the query above to get this:
4507|Business
4515|Business
7882|Business
7889|Business
7889|Business
8004|Business
4761|Design
5594|Design
5594|Design
5594|Design
7736|Design
7736|Design
7736|Design
3132|Developer
3132|Developer
3132|Developer
4826|Developer
5403|Developer
As you can see from the data, Business should be 5, not 4, etc. At least that is what my eyes tell me. :)
I am running this inside a FileMaker 12 solution using it's internal ExecuteSQL call. Don't be concerned by that too much, though: the code should be the same as nearly anything else. :)
Any help would be appreciated.
Thanks,
J
Try using a subquery:
SELECT COUNT(*), Type
FROM (SELECT DISTINCT B.ID_FK, A.Type Type
FROM A
INNER JOIN B ON B.ID_FK = A.ID
WHERE Date > 5/1/2013 and Date < 5/2/2013) x
GROUP BY Type
ORDER BY Type
This could be a FileMaker issue, have you seen this post on the FileMaker forum? It describes the same issue (a count distinct smaller by 1) with 11V3 back in 03/2012 with a plug in, then updated with same issue with 12v3 in 11/2012 with ExecuteSQL. It didn't seem to be resolved in either case.
Other considerations might be if there are any referential integrity constraints on the joined tables, or if you can get a query execution plan, you might find it is executing the query differently than expected. not sure if FileMaker can do this.
I like Barmar's suggestion, it would sort twice.
If you are dealing with a bug, directing the COUNT DISTINCT, Join and/or Group By by structuring the query to make them happen at different times might work around it:
SELECT COUNT (DISTINCT x.ID), x.Type
FROM (SELECT A.ID ID, A.Type Type
FROM A
INNER JOIN B ON B.ID_FK = A.ID
WHERE B.Date > 5/1/2013 and B.Date < 5/2/2013) x
GROUP BY Type
ORDER BY Type
you might also try replacing B.ID_FK with A.ID, who knows what context it applies, such as:
SELECT COUNT (DISTINCT A.ID), A.Type

How do you explicitly show rows which have count(*) equal to 0

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.