Empty group by with count returns null - sql

I have a query with a count/group by - If no person with the name 'Bob' is found then it returns no rows at all because the GROUP BY is on an empty set - null is returned for the count - I'd like to change the behaviour so that count returns 0 and not null.
select p.Id as personId, count(*) as alias1 from
Table1 as alias2
join Table2 as alias3 on alias3.personId = alias1.Id
where Name = 'Bob'
group by p.Id

Your example was confusing because you're using some alias that don't exist.
Try to use LEFT JOIN.
with
Table1 as
(select 1 as Id, 'Bob' as Name),
Table2 as
(select 2 as personId)
select alias1.Id as personId, count(alias2.personId)
from Table1 as alias1
left join Table2 as alias2 on alias1.Id = alias2.personId
where Name = 'Bob'
group by alias1.Id

Please see:
Count Returning blank instead of 0
Essentially, you can't use GROUP BY and expect no results to return a row.

Related

SQL select 1 to many within the same row

I have a table with 1 record, which then ties back to a secondary table which can contain either no match, 1 match, or 2 matches.
I need to fetch the corresponding records and display them within the same row which would be easy using left join if I just had 1 or no matches to tie back, however, because I can get 2 matches, it produces 2 records.
Example with 1 match:
Select T1.ID, T1.Person1, T2.Owner
From T1
Left Join T2
ON T1.ID = T2.MatchID
Output
ID Person1 Owner1
----------------------
1 John Frank
Example with 2 match:
Select T1.ID, T1.Person1, T2.Owner
From T1
Left Join T2
ON T1.ID = T2.MatchID
Output
ID Person1 Owner
----------------------
1 John Frank
1 John Peter
Is there a way I can formulate my select so that my output would reflect the following When I have 2 matches:
ID Person1 Owner1 Owner2
-------------------------------
1 John Frank Peter
I explored Oracle Pivots a bit, however couldn't find a way to make this work. Also explored the possibility of using left join on the same table twice using MIN() and MAX() when fetching the matches, however I can only see myself resorting this as a "no other option" scenario.
Any suggestions?
** EDIT **
#ughai - Using CTE does address the issue to some extent, however when attempting to retrieve all of the records, the details derived from this common table isn't showing any records on the LEFT JOIN unless I specify the "MatchID" (CASE_MBR_KEY) value, meaning by removing the "where" clause, my outer joins produce no records, even though the CASE_MBR_KEY values are there in the CTE data.
WITH CTE AS
(
SELECT TEMP.BEAS_KEY,
TEMP.CASE_MBR_KEY,
TEMP.FULLNAME,
TEMP.BIRTHDT,
TEMP.LINE1,
TEMP.LINE2,
TEMP.LINE3,
TEMP.CITY,
TEMP.STATE,
TEMP.POSTCD,
ROW_NUMBER()
OVER(ORDER BY TEMP.BEAS_KEY) R
FROM TMP_BEN_ASSIGNEES TEMP
--WHERE TEMP.CASE_MBR_KEY = 4117398
)
The reason for this is because the ROW_NUMBER value, given the amount of records won't necessarily be 1 or 2, so I attempted the following, but getting ORA-01799: a column may not be outer-joined to a subquery
--// BEN ASSIGNEE 1
LEFT JOIN CTE BASS1
ON BASS1.CASE_MBR_KEY = C.CASE_MBR_KEY
AND BASS1.R IN (SELECT min(R) FROM CTE A WHERE A.CASE_MBR_KEY = C.CASE_MBR_KEY)
--// END BA1
--// BEN ASSIGNEE 2
LEFT JOIN CTE BASS2
ON BASS2.CASE_MBR_KEY = C.CASE_MBR_KEY
AND BASS2.R IN (SELECT MAX(R) FROM CTE B WHERE B.CASE_MBR_KEY = C.CASE_MBR_KEY)
--// END BA2
** EDIT 2 **
Fixed the above issue by moving the Row number clause to the "Where" portion of the query instead of within the JOIN clause. Seems to work now.
You can use CTE with ROW_NUMBER() with 2 LEFT JOIN OR with PIVOT like this.
SQL Fiddle
Query with Multiple Left Joins
WITH CTE as
(
SELECT MatchID,Owner,ROW_NUMBER()OVER(ORDER BY Owner) r FROM t2
)
select T1.ID, T1.Person, t2.Owner as Owner1, t3.Owner as Owner2
FROM T1
LEFT JOIN CTE T2
ON T1.ID = T2.MatchID AND T2.r = 1
LEFT JOIN CTE T3
ON T1.id = T3.MatchID AND T3.r = 2;
Query with PIVOT
WITH CTE as
(
SELECT MatchID,Owner,ROW_NUMBER()OVER(ORDER BY Owner) R FROM t2
)
SELECT ID, Person,O1,O2
FROM T1
LEFT JOIN CTE T2
ON T1.ID = T2.MatchID
PIVOT(MAX(Owner) FOR R IN (1 as O1,2 as O2));
Output
ID PERSON OWNER1 OWNER2
1 John Maxwell Peter
If you know there are at most two matches, you can also use aggregation:
Select T1.ID, T1.Person1,
MIN(T2.Owner) as Owner1,
(CASE WHEN MIN(t2.Owner) <> MAX(t2.Owner) THEN MAX(t2.Owner) END) as Owner2
From T1 Left Join
T2
on T1.ID = T2.MatchID
Group By t1.ID, t1.Person1;

Getting count of records in child table using select statement

I have a stored procedure in which i am trying to select all the columns of a table Table 1. There is another table which uses Table1 primary key as foreign key. I want to count number of records in this foreign key table with that select like this:
SELECT *, count(*) VacancyCount
FROM Table1 hc
LEFT JOIN Table2 hv
on hc.CompanyID = hv.CompanyID
WHERE hc.Deleted = 0
group by hc.CompanyID
ORDER BY NameLang1
but it gives error:
Column 'dbo.Table1.NameLang1' is invalid in the select list because it
is not contained in either an aggregate function or the GROUP BY
clause.
Please suggest how to fix this?
Please try:
select
*,
(select COUNT(*) from Table2 hv where hv.CompanyID=hc.CompanyID) VacancyCount
from Table1 hc
where
hc.Deleted = 0
order by hc.NameLang1, VacancyCount desc
for ordering using the new column
select * from(
select
*,
CONVERT(NVARCHAR(100), (select COUNT(*) from Table2 hv where hv.CompanyID=hc.CompanyID)) VacancyCount
from Table1 hc
where
hc.Deleted = 0
)x
Order by CASE WHEN #OrderByParam = 1 THEN NameLang1 ELSE VacancyCount END
Provided column NameLang1 and VacancyCount are of same datatype.
You're doing grouping wrong. You need to use all the columns from Table 1 in SELECT instead of '*' and in GROUP BY clause as well.
Or you can try a different approach like this:
SELECT *
FROM Table1 hc
LEFT JOIN (SELECT CompanyID, COUNT(*) cnt FROM Table2 GROUP BY CompanyID) hv
on hc.CompanyID = hv.CompanyID
WHERE hc.Deleted = 0
ORDER BY NameLang1
You will have to list every column in the GROUP BY clause
These columns are those in the SELECT * bit.
This would be correct ANSI SQL anyway.
SELECT * itself is bad anyway: it is always better to explicitly list columns
Try in this way include column list in group by
SELECT column1,column2,column3..,NameLang1,count(*) VacancyCount
FROM Table1 hc
LEFT JOIN Table2 hv
on hc.CompanyID = hv.CompanyID
WHERE hc.Deleted = 0
group by column1,column2,column3
ORDER BY NameLang1

COUNT() over result of Except

I have a query like:
SELECT
id
FROM
table1
INNER JOIN
...
WHERE
...
AND eventtype IN (2000120, 2000121, 2000122, 2000123, 2000130)
EXCEPT
SELECT
id
FROM
table1
INNER JOIN
...
WHERE
...
AND eventtype IN (2000123,2000130,2000134,2000135)
Note that the queries are both identical except the last where-clause.
I would now like to count the number of records returned by this above query.
How to?
Many thanks
use COUNT and wrap it inside a SUBQUERY
SELECT COUNT(ID)
FROM (
SELECT id
FROM table1
INNER JOIN...
WHERE...
AND eventtype IN ( 2000120, 2000121, 2000122, 2000123, 2000130 )
EXCEPT
SELECT id
FROM table1
INNER JOIN...
WHERE...
AND eventtype IN ( 2000123, 2000130, 2000134, 2000135 )
) s
you just need the first query for what you want, you don't have to include the 2000130 value if you don't need it and so the other values that you don't want to be shown in you query.
SELECT
id
FROM
table1
INNER JOIN
...
WHERE
...
AND eventtype IN (2000120, 2000121, 2000122, 2000123)
If you need to exclude some values from the some query you can use
AND eventtype NOT IN (2000130)
But not both at once. And to count just a regular use SELECT COUNT(id) or a subquery if you want.
Also you can use EXISTS with INTERSECT sub-query
SELECT COUNT(ID)
FROM table1 t1 INNER JOIN ...
WHERE ... AND eventtype IN (2000120, 2000121, 2000122, 2000123, 2000130)
AND NOT EXISTS (
SELECT 1
FROM table1 t2 INNER JOIN ...
WHERE ... AND eventtype IN (2000123, 2000130, 2000134, 2000135)
AND EXISTS (SELECT t1.ID
INTERSECT
SELECT t2.ID))

Multiple count based on dynamic criteria

I have two database for which I want to compare the amount of times a case appears.
TAB1:
ID Sequence
A2D 1
A2D 2
A2D 3
A3D 1
TAB2:
ID Sequence
A2D 1
A2D 2
A3D 1
A3D 2
Now, for this example, I am trying to get this result:
ID Table1 Table2
A2D 3 2
A3D 1 2
I have tried these code without any success:
SELECT R1.ID as ID, COUNT(R1.ID) as Table1,
COUNT(R2.ID) as Table2
FROM TAB1 AS R1, TAB2 AS R2
WHERE R1.ID = R2.ID
GROUP BY R1.ID
This one gave me wrong count values...
Also, this one simply crash:
select
(
select count(*) as Table1
from TAB1
where ID = R1.ID
),(
select count(*) as Table2
from TAB2
where ID= R1.ID
)
FROM TAB1 AS R1
As you can see though, I am trying to have my criteria dynamic. Most examples I found were including basic hard-coded criteria. But for my case, I want the query to look at my first table ID, count the amount of time it appears, do it for the 2nd table with the same ID, then move on to the next ID.
If my question lacks information or is confusing just ask me, I'll do my best to be more precise.
Thanks in advance !
Here I am using a UNION ALL as a subquery
SELECT ID, SUM(T1) AS Table1, SUM(T2) AS Table2
FROM
(SELECT ID, COUNT(ID) AS T1, 0 AS T2 FROM TAB1 GROUP BY ID
UNION ALL
SELECT ID, 0 AS T1, COUNT(ID) AS T2 FROM TAB2 GROUP BY ID)
GROUP BY ID
HAVING SUM(T1)>0 AND SUM(T2)>0
I used a different approach, but unfortunately I have to use two queries, i still don't know if they can be combined together. The first one is just for making sums of both tables, and combining the results:
SELECT "Tab1" AS [Table], Tab1.ID, Count(*) AS Total
FROM Tab1
GROUP BY "Tab1", Tab1.ID
UNION SELECT "Tab2" AS [Table], Tab2.ID, Count(*) AS Total
FROM Tab2
GROUP BY "Tab2", Tab2.ID
and, since Access supports Pivot queries, you can use this:
TRANSFORM Sum(qrySums.[Total]) AS Total
SELECT qrySums.[ID]
FROM qrySums
GROUP BY qrySums.[ID]
PIVOT qrySums.[Table];
Not sure if I understand your question, but you could try something like this:
SELECT DISTINCT t.ID,
(SELECT COUNT(ID) FROM R1 WHERE ID = t.ID) AS table1,
(SELECT COUNT(ID) FROM R2 WHERE ID = t.ID) AS table2
FROM table1 t
To get the desired results, I broke it down into two sub-queries (R1SQ and R2SQ) and a main UNION query - R1R2 that uses inner, left and right joins to include all row entries including those rows that do not appear in both tables:
R1SQ
SELECT R1.Builder, Count(R1.Builder) AS Table1
FROM R1
GROUP BY R1.Builder;
R2SQ
SELECT R2.Builder_E, Count(R2.Builder_E) AS Table2
FROM R2
GROUP BY R2.Builder_E;
R1R2
SELECT R1SQ.Builder, R1SQ.Table1, R2SQ.Table2
FROM R1SQ INNER JOIN R2SQ ON R1SQ.Builder = R2SQ.Builder_E
UNION
SELECT R1SQ.Builder, R1SQ.Table1, 0 AS Table2
FROM R1SQ LEFT JOIN R2SQ ON R1SQ.Builder = R2SQ.Builder_E
WHERE (((R2SQ.Builder_E) Is Null))
UNION
SELECT R2SQ.Builder_E, 0 AS Table1, R2SQ.Table2
FROM R1SQ RIGHT JOIN R2SQ ON R1SQ.Builder = R2SQ.Builder_E
WHERE (((R1SQ.Builder) Is Null))
ORDER BY R1SQ.Builder;

How to get the result of select statement grouped by a column to perform join statement on it?

How to get the result of select statement grouped by a column to perform join statement on it ?
You should enclose the select statement that contains the GROUP BY instead of one of the joined table, something like this:
SELECT t1.Id, ....
FROM Table1 t1
INNER JOIN
(
SELECT Id, COUNT(*)
FROM Table2
GROUP BY Id
) t2 ON t1.Id = t2.Table1Id
This might help you:
suppose there are two table
1.student
(stud_id pk)
(branch_id fk)
2. branch
(branch_id pk)
(branch name varchar)
(city varchar)
select * from student s,branch b where s.branch_id=b.branch_id group by b.city