SQL join including all rows from one table irrespective of how many are represented in the other table - sql

Following on from my previous question here.
I have two tables:
TableA
TableB
I want to output the following:
Instead, my query gives me this:
Here is my SQL statement:
SELECT TableA.BU, TableB.count_invalid_date
FROM TableA
LEFT JOIN TableB ON TableA.BU = TableB.BU
WHERE TableB.Month = 8
GROUP BY TableA.BU, TableB.count_invalid_date;
Is there a single SQL statement that can give me what I want?
SQL Fiddle is here: http://sqlfiddle.com/#!6/2ab0f/1
Thanks in advance!

Try this:
SELECT
TableA.BU,
TableB.count_invalid_date
FROM
TableA
LEFT JOIN TableB ON TableA.BU = TableB.BU and TableB.Month = 8
GROUP BY
TableA.BU,
TableB.count_invalid_date;
When doing an outer join, you can't reference any of the table in where clause or otherwise it will turn it into inner join.

Problem:
Since your where clause says TableB.Month=8, that is why other rows are getting eliminated from the result.
Solution:
Add one more condition to the where clause.
SELECT TableA.BU, TableB.count_invalid_date
FROM TableA LEFT JOIN
TableB ON TableA.BU=TableB.BU
WHERE (TableB.Month=8 OR TableB.Month IS NULL)
GROUP BY TableA.BU, TableB.count_invalid_date;
Result:
BU COUNT_INVALID_DATE
APAC (null)
EMEA 3
SG (null)
US (null)
See result in SQL Fiddle.

Related

SQL join including all rows from one table irrespective of how many are represented in the other

I have two tables:
I want to output the following:
I tried this statement:
SELECT TableA.bu_code
, SUM(TableB.count_invalid_date) AS TotalInvDate
FROM TableA
LEFT JOIN TableB ON TableA.bu_code = TableB.bu_code
GROUP BY TableA.bu_code
But it doesn't show every row represented in TableA, instead it does this:
Is there a single SQL statement that can output what I want?
You could use a left join after performing the group by:
SELECT a.bu_code, COALESCE (TotalInvDate, 0)
FROM TableA a
LEFT JOIN (SELECT bu_code, SUM(count_invalid_date) AS TotalInvDate
FROM TableB
GROUP BY bu_code) b ON a.bu_code = b.bu_code
There may be orphaned TableB rows without a parent row in TableA.
If so, use this GROUP BY syntax to see them.
GROUP BY ROLLUP(TableA.bu_code)
Refer to this Microsoft SQL-Server page on the GROUP BY clause for more details on the ROLLUP option.
SELECT A.bu_code AS [bu_code],
ISNULL(sum( B.count_invalid_date),0) AS [TotalInvDate]
FROM
TableA A
left JOIN
TableB B
ON
A.bu_code=B.bu_code
GROUP BY
A.bu_code

sql left join returns

I am trying to run a left join on 2 tables. I do not have a group by and the only where condition i have is on the second table. But, the returned rows are less than the first table. isn't the left join suppose to bring all the data from the first table?
Here is my SQL:
select *
from tbl_a A left join tbl_b B
ON
A.Cnumber=B.Cnumber
and A.CDNUmber=B.CDNumber
and abs(A.duration - B.Duration)<2
and substr(A.text,1,3)||substr(A.text,5,8)||substr(A.text,9,2)=substr(B.text,1,8)
where B.fixed = 'b580'
There are 140,000 records in table A but the result returned is less than 100,000 records. What is the problem and how can I solve it?
As soon as you put a condition in the WHERE clause that references the right table and doesn't accommodate the NULLs that will be produced when the join is unsuccessful, you've transformed it (effectively) back into an INNER JOIN.
Try:
where B.fixed = 'b580' OR B.fixed IS NULL
Or add this condition to the ON clause for the JOIN.
You should add the where clause to the join:
select *
from tbl_a A left join tbl_b B
ON
A.Cnumber=B.Cnumber
and A.CDNUmber=B.CDNumber
and abs(A.duration - B.Duration)<2
and substr(A.text,1,3)||substr(A.text,5,8)||substr(A.text,9,2)=substr(B.text,1,8)
and B.fixed = 'b580'
If you use where statemen all records where b is not existing will not returned.

NOT IN converted to LEFT JOIN giving different result

please help on below query
select * from processed_h where c_type not in (select convert(int,n_index) from index_m where n_index <>'0') **-- 902 rows**
select * from processed_h where c_type not in (2001,2002,2003) **-- 902 rows**
select convert(int,n_index) from index_m where n_index <>'0' **--- 2001,2002,2003**
I tried to convert the not in to LEFT JOIN as below but it is giving me 40,000 rows returned what I am doing wrong
select A.* from processed_h A LEFT JOIN index_m B on A.c_type <> convert(int,B.n_index) and B.n_index <>'0' --40,000 + rows
A LEFT JOIN returns ALL rows from the "left-hand" table regardless of whether the condition matches or not, which is why you are getting the "extra" rows.
An INNER JOIN might give you the same number of rows, but if there are multiple matches in the "right-hand" table then you'll still get more rows than you expect.
If NOT IN gives you the expected results then I'd stick with that. You probably aren;t going to see significant improvements with a join. The only reason I would change to an INNER JOIN is if I needed columns from the joined table in my output.
For the equivalent of a NOT IN using a left join, you need to link the tables as though the results in the linked table should be IN the resultset, then select only those records where the outer joined table did not return a record - like so:
select A.* from processed_h A
LEFT JOIN index_m B on A.c_type = convert(int,B.n_index) and B.n_index <>'0'
WHERE B.n_index IS NULL
However, you might get better performance using a NOT EXISTS query instead:
select A.* from processed_h A
where not exists
(select 1 from index_m B where B.n_index <>'0' and A.c_type = convert(int,B.n_index) )

SQL to return matches and non-matches

How do I return all the rows from two tables including the matches? For example, if I have a account table and order table with an account ID field in common I want to return the matches from both tables as well as the non-matches.
I am using SQL Server 2005
Thanks.
I think you need FULL OUTER JOIN:
SELECT *
FROM Table1 T1
FULL OUTER JOIN Table2 T2 ON T1.AccountId = T2.AccountId
Good luck.
If you want to get both MATCHED and UNMATCHED records from both tables use FULL JOIN (or FULL OUTER JOIN). Also you can find what records are matched or unmatched using a CASE as below. Sql-Fiddle DEMO
select isnull(a.accountId,o.accountId) accId, AccName,ProName,
case when AccName+ProName is null then 'No'
else 'Yes' end as IsMatched
from Accs a FULL JOIN Orders o on a.accountId = o.accountId
order by IsMatched
--Example results
AccId AccName ProName IsMatched
1 X (null) No
10 (null) Apple No
2 Y Orange Yes
3 Z Mango Yes

Outer Join with Where returning Nulls

Hi I have 2 tables. I want to list
all records in table1 which are present in
table2
all records in table2 which are not present in table1 with a where condition
Null rows will be returned by table1 in second condition but I am unable to get the query working correctly. It is only returning null rows
SELECT
A.CLMSRNO,A.CLMPLANO,A.GENCURRCODE,A.CLMNETLOSSAMT,
A.CLMLOSSAMT,A.CLMCLAIMPRCLLOSSSHARE
FROM
PAKRE.CLMCLMENTRY A
RIGHT OUTER JOIN (
SELECT
B.CLMSRNO,B.UWADVICETYPE,B.UWADVICENO,B.UWADVPREMCURRCODE,
B.GENSUBBUSICLASS,B.UWADVICENET,B.UWADVICEKIND,B.UWADVYEAR,
B.UWADVQTR,B.ISMANUAL,B.UWCLMNOREFNO
FROM
PAKRE.UWADVICE B
WHERE
B.ISMANUAL=1
) r
ON a.CLMSRNO=r.CLMSRNO
ORDER BY
A.CLMSRNO DESC;
Which OS are you using ?
Table aliases are case sensistive on some platforms, which is why your join condition ON a.CLMSRNO=r.CLMSRNO fails.
Try with A.CLMSRNO=r.CLMSRNO and see if that works
I'm not understanding your first attempt, but here's basically what you need, I think:
SELECT *
FROM TABLE1
INNER JOIN TABLE2
ON joincondition
UNION ALL
SELECT *
FROM TABLE2
LEFT JOIN TABLE1
ON joincondition
AND TABLE1.wherecondition
WHERE TABLE1.somejoincolumn IS NULL
I think you may want to remove the subquery and put its columns into the main query e.g.
SELECT A.CLMSRNO, A.CLMPLANO, A.GENCURRCODE, A.CLMNETLOSSAMT,
A.CLMLOSSAMT, A.CLMCLAIMPRCLLOSSSHARE,
B.CLMSRNO, B.UWADVICETYPE, B.UWADVICENO, B.UWADVPREMCURRCODE,
B.GENSUBBUSICLASS, B.UWADVICENET, B.UWADVICEKIND, B.UWADVYEAR,
B.UWADVQTR, B.ISMANUAL, B.UWCLMNOREFNO
FROM PAKRE.CLMCLMENTRY A
RIGHT OUTER JOIN PAKRE.UWADVICE B
ON A.CLMSRNO = B.CLMSRNO
WHERE B.ISMANUAL = 1
ORDER
BY A.CLMSRNO DESC;