Query using COUNT returns records where the count is positive only - sql

Good day everyone.
Consider this portion of a relational SQLite database:
floors(number) - rooms(number, #floorNumber)
I aim to query for the number of rooms per floor. This is my attempt:
select floors.number, count(rooms.floornumber)
from floors, rooms where floors.number=rooms.floornumber
group by floors.number, rooms.floornumber;
Example:
1|5
2|7
3|5
4|3
The issue is that I also would like the query to return records where the floor contains 0 rooms (for example floor number 5 exists in the "floors" table but isn't shown in the query result).
Your assistance is appreciated. Thank you.

Never use commas in the FROM clause. Always use proper, explicit JOIN syntax.
You need a LEFT JOIN, but you cannot even see what you need because of the way that your query is written.
select f.number, count(r.floornumber)
from floors f left join
rooms r
on f.number = r.floornumber
group by f.number;

Related

Athena/Presto | Can't match ID row on self join

I'm trying to get the bi-grams on a string column.
I've followed the approach here but Athena/Presto is giving me errors at the final steps.
Source code so far
with word_list as (
SELECT
transaction_id,
words,
n,
regexp_extract_all(f70_remittance_info, '([a-zA-Z]+)') as f70,
f70_remittance_info
FROM exploration_transaction
cross join unnest(regexp_extract_all(f70_remittance_info, '([a-zA-Z]+)')) with ordinality AS t (words, n)
where cardinality((regexp_extract_all(f70_remittance_info, '([a-zA-Z]+)'))) > 1
and f70_remittance_info is not null
limit 50 )
select wl1.f70, wl1.n, wl1.words, wl2.f70, wl2.n, wl2.words
from word_list wl1
join word_list wl2
on wl1.transaction_id = wl2.transaction_id
The specific issue I'm having is on the very last line, when I try to self join the transaction ids - it always returns zero rows. It does work if I join only by wl1.n = wl2.n-1 (the position on the array) which is useless if I can't constrain it to a same id.
Athena doesn't support the ngrams function by presto, so I'm left with this approach.
Any clues why this isn't working?
Thanks!
This is speculation. But I note that your CTE is using limit with no order by. That means that an arbitrary set of rows is being returned.
Although some databases materialize CTEs, many do not. They run the code independently each time it is referenced. My guess is that the code is run independently and the arbitrary set of 50 rows has no transaction ids in common.
One solution would be to add order by transacdtion_id in the subquery.

Missing rows that are only on one table on FULL OUTER JOIN in PostgreSQL

I have 2 tables remittance and draft where I'm trying to find the difference between what was remitted and drafted.
This is what I have so far, but it doesn't give me the records that are only on one of the tables
SELECT remittance.loan_no, remittance.inv_loan_no, remittance.ll_remittance,
draft.fm_loan_number, draft.draft_amount,
(remittance.ll_remittance) - (draft.draft_amount) AS difference
FROM remittance FULL JOIN draft
ON remittance_.inv_loan_no = draft.fm_loan_number
WHERE (remittance.ll_remittance) - (draft.draft_amount)<> 0.00;
Could it be because I when I do the difference the missing remittance or draft amounts have null values in them and that's why I'm not getting any results for the difference.
I thought FULL JOIN would give me the loans that are only on one of the tables and NULL in other tables column.
Thank you,
Here is the sample data:
Remittance Table, Draft Table, Query Results
I have highlighted the loans in red that are not showing up in the Query Results
Could it be because I when I do the difference the missing remittance or draft amounts have null values in them and that's why I'm not getting any results for the difference.
Yes! Adding a where clause to a full join is always tricky because the filtering takes place on the joined data set.
However, I don't think there should be any problems in placing that difference query in the on clause instead.
SELECT remittance.loan_no, remittance.inv_loan_no, remittance.ll_remittance,
draft.fm_loan_number, draft.draft_amount,
(remittance.ll_remittance) - (draft.draft_amount) AS difference
FROM remittance FULL JOIN draft
ON remittance_.inv_loan_no = draft.fm_loan_number
AND (remittance.ll_remittance) - (draft.draft_amount)<> 0.00;
If you have only one row in each table for each loan, then coalesce() suffices for your purposes:
SELECT r.loan_no, r.inv_loan_no, r.ll_remittance,
d.fm_loan_number, d.draft_amount,
coalesce(r.ll_remittance, 0) - coalesce(d.draft_amount, 0) AS difference
FROM remittance r FULL JOIN
draft d
ON r.inv_loan_no = d.fm_loan_number
WHERE coalesce(r.ll_remittance, 0) <> coalesce(d.draft_amount, 0);
If there are multiple rows, then you will need to pre-aggregate.
Here is a SQL Fiddle.

MS Access 2013, How to add totals row within SQL

I'm in need of some assistance. I have search and not found what I'm looking for. I have an assigment for school that requires me to use SQL. I have a query that pulls some colunms from two tables:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
I need to add a Totals row at the bottom to count the CourseNo and Sum the CrHrs. It has to be done through SQL query design as I need to paste the code. I know it can be done with the datasheet view but she will not accept that. Any advice?
To accomplish this, you can union your query together with an aggregation query. Its not clear from your question which columns you are trying to get "Totals" from, but here's an example of what I mean using your query and getting counts of each (kind of useless example - but you should be able to apply to what you are doing):
SELECT
[Course].[CourseNo]
, [Course].[CrHrs]
, [Sections].[Yr]
, [Sections].[Term]
, [Sections].[Location]
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = [spring]
UNION ALL
SELECT
"TOTALS"
, SUM([Course].[CrHrs])
, count([Sections].[Yr])
, Count([Sections].[Term])
, Count([Sections].[Location])
FROM
[Course]
INNER JOIN [Sections] ON [Course].[CourseNo] = [Sections].[CourseNo]
WHERE [Sections].[Term] = “spring”
You can prepare your "total" query separately, and then output both query results together with "UNION".
It might look like:
SELECT Course.CourseNo, Course.CrHrs, Sections.Yr, Sections.Term, Sections.Location
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring"
UNION
SELECT "Total", SUM(Course.CrHrs), SUM(Sections.Yr), SUM(Sections.Term), SUM(Sections.Location)
FROM Course
INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term="spring";
Whilst you can certainly union the aggregated totals query to the end of your original query, in my opinion this would be really bad practice and would be undesirable for any real-world application.
Consider that the resulting query could no longer be used for any meaningful analysis of the data: if displayed in a datagrid, the user would not be able to sort the data without the totals row being interspersed amongst the rest of the data; the user could no longer use the built-in Totals option to perform their own aggregate operation, and the insertion of a row only identifiable by the term totals could even conflict with other data within the set.
Instead, I would suggest displaying the totals within an entirely separate form control, using a separate query such as the following (based on your own example):
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM Course INNER JOIN Sections ON Course.CourseNo = Sections.CourseNo
WHERE Sections.Term = "spring";
However, since CrHrs are fields within your Course table and not within your Sections table, the above may yield multiples of the desired result, with the number of hours multiplied by the number of corresponding records in the Sections table.
If this is the case, the following may be more suitable:
SELECT Count(Course.CourseNo) as Courses, Sum(Course.CrHrs) as Hours
FROM
Course INNER JOIN
(SELECT DISTINCT s.CourseNo FROM Sections s WHERE s.Term = "spring") q
ON Course.CourseNo = q.CourseNo

How would I join a value of zero when a left join doesn't match?

I'm looking to join the field Count from the query qCallCount to the results of the query qCustomers. I think I want to use a left join because there are customers in the qCustomers dataset that won't have a match in the qCallCount dataset, but I don't want to drop them from the results.
My current query...
SELECT a.CustomerID, b.Count, a.Customer_Segmentation
FROM qCustomers AS a LEFT JOIN qCallCount AS b ON a.CustomerID=b.CustomerID;
My question is, is there a way to make the value for the Count field in the result of this query have a value of 0 if there's no match in qCallCount?
If this was Excel I'd write an =IFERROR(VLOOKUP(CustomerID, qCallCount, Count, False),0)
Why do I need this? I'm ultimately going to run an average of count avg(Count) as Average and it's important for those failed matches to be treated as zero, because that's what they actually are.
Thanks!
Check null value in MS Access Query
You can check for IsNull(b.Count, 0)
Is Count the name of a column, or are you using the function Count?
The VB/VBA/MS Access null-coalescing function is Nz. (In VB6, IsNull is not the same as in SQL Server--it's a different function that returns a Boolean indicating whether the value is Null.) So it would look like this:
SELECT
a.CustomerID,
Nz(b.Count, 0) AS CallCount,
a.Customer_Segmentation
FROM
qCustomers AS a
LEFT JOIN qCallCount AS b ON a.CustomerID=b.CustomerID;

Oracle viewing highest record

I have a Module and Students table as well as a linker table called Results. I am trying to display only one record of the student with the highest result for the specific module but i cannot get it to work. Here is my sql syntax so far:
SELECT S.ST_FNAME, S.ST_LNAME, M.MOD_NAME, R.RES_GRADE
FROM STUDENT S, MODULE M, RESULTS R
WHERE S.ST_ID=R.ST_ID AND M.MOD_ID=R.MOD_ID
AND M.MOD_ID=503;
At the moment it displays all the students and their results for the specific module.
help would be appreciated
To get a single value for a group of rows, use GROUP BY (in your case, with MAX to get the maximum):
SELECT
S.ST_FNAME,
S.ST_LNAME,
M.MOD_NAME,
max(R.RES_GRADE) as max_grade
FROM STUDENT S
JOIN RESULTS R on S.ST_ID = R.ST_ID
JOIN MODULE M on R.MOD_ID = M.MOD_ID
WHERE M.MOD_ID=503
GROUP BY s.st_fname, s.st_lname, m.mod_name;
I've also converted your old-style joins to ANSI-style joins - using ANSI style is preferred by most people nowadays.
SQL Fiddle