sql server programming:
#tmpA contains 1 column named code and 14 rows -- 6 'A's, 4 'B's, 4 'C's #tmpB1 contains 1 column named code and 2 rows -- 1 'A' and 1 'B' #tmpB2 contains 1 column named code and 11 rows -- 5 'A's, 2 'B's, and 4 'C's I need to select rows from #tmpA where the count of individual codes does not match the sum(count) of those individual code counts from #tmpB1 and #tmpB2. In my scenario here, #tmpA contains 6 'A's and #tmpB1 contains 1 'A' and #tmpB2 contains 5 'A's. #tmpB1 + #tmpB2 count of 'A's = 6 so I dont want to select the 'A's from #tmpA since the counts match. Then #tmpA contains 4 'C's, #tmpB1 contains 0 'C's and #tmpB2 contains 4 'C's, so the count of 'C's from #tmpB1 + #tmpB2 = 4 = the Count of 'C's in #tmpA. Dont want 'C's from #tmpA since the count of 'C's match. Now #tmpA contains 4 'B's, #tmpB1 contains 1 'B and #tmpB2 contains 2 'B's. The count of B's from #tmpB1 + #tmpB2 = 3 which is not equal to 4 -- the 4 'B's in #tmpA. I need to select the rows containing 'B' from #tmpA since the counts do not match. what would the tSql look like to achieve this pull? CREATE TABLE #tmpA(code varchar(1)) CREATE TABLE #tmpB1(code varchar(1)) CREATE TABLE #tmpB2(code varchar(1)) INSERT INTO #tmpA SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'B' UNION ALL SELECT 'B' UNION ALL SELECT 'B' UNION ALL SELECT 'B' UNION ALL SELECT 'C' UNION ALL SELECT 'C' UNION ALL SELECT 'C' UNION ALL SELECT 'C' INSERT INTO #tmpB1 SELECT 'A' UNION ALL SELECT 'B' INSERT INTO #tmpB2 SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'A' UNION ALL SELECT 'B' UNION ALL SELECT 'B' UNION ALL SELECT 'C' UNION ALL SELECT 'C' UNION ALL SELECT 'C' UNION ALL SELECT 'C' I was experimenting with something like the following SELECT count(t1.*) FROM #tmpa t1 join (select * FROM #tmpB1 WHERE code = 'A' UNION all SELECT * FROM #tmpB2 WHERE code = 'A') t2 ON t1.code = t2.code where t1.code = 'A' but this error'd out. thanks,
slight modification in my setup. I added an additional field to give the rows some uniqueness. CREATE TABLE #tmpA(fname varchar(10), code varchar(1)) CREATE TABLE #tmpB1(fname varchar(10), code varchar(1)) CREATE TABLE #tmpB2(fname varchar(10), code varchar(1)) INSERT INTO #tmpA SELECT 'bill', 'A' UNION ALL SELECT 'tim', 'A' UNION ALL SELECT 'sue', 'A' UNION ALL SELECT 'tom', 'A' UNION ALL SELECT 'bob', 'A' UNION ALL SELECT 'steve', 'A' UNION ALL SELECT 'bill', 'B' UNION ALL SELECT 'tim', 'B' UNION ALL SELECT 'sue', 'B' UNION ALL SELECT 'bob', 'B' UNION ALL SELECT 'bill', 'C' UNION ALL SELECT 'tim', 'C' UNION ALL SELECT 'sue', 'C' UNION ALL SELECT 'bob', 'C' INSERT INTO #tmpB1 SELECT 'bill', 'A' UNION ALL SELECT 'bill', 'B' INSERT INTO #tmpB2 SELECT 'tim', 'A' UNION ALL SELECT 'sue', 'A' UNION ALL SELECT 'tom', 'A' UNION ALL SELECT 'bob', 'A' UNION ALL SELECT 'steve', 'A' UNION ALL SELECT 'tim', 'B' UNION ALL SELECT 'sue', 'B' UNION ALL SELECT 'bill', 'C' UNION ALL SELECT 'tim', 'C' UNION ALL SELECT 'sue', 'C' UNION ALL SELECT 'bob', 'C' experiment: SELECT t1.* FROM #tmpa t1 join (select * FROM #tmpB1 WHERE fname = 'bill' AND code = 'A' UNION all SELECT * FROM #tmpB2 WHERE fname = 'bill' AND code = 'A') t2 ON t1.code = t2.code where t1.code = 'A' still can't get the counts though
Try: SELECT * FROM ( SELECT code, COUNT(*) AS cnt FROM [#tmpA] GROUP BY code ) AS a LEFT OUTER JOIN ( SELECT code, COUNT(*) AS cnt FROM ( SELECT * FROM [#tmpB1] UNION ALL SELECT * FROM [#tmpB2] ) AS t GROUP BY code ) AS b ON a.code = b.code WHERE b.code IS NULL OR a.cnt != b.cnt GO -- OR SELECT * FROM ( SELECT code, COUNT(*) AS cnt FROM [#tmpA] GROUP BY code ) AS a FULL OUTER JOIN ( SELECT code, COUNT(*) AS cnt FROM ( SELECT * FROM [#tmpB1] UNION ALL SELECT * FROM [#tmpB2] ) AS t GROUP BY code ) AS b ON a.code = b.code WHERE a.code IS NULL OR b.code IS NULL OR a.cnt != b.cnt GO AMB [quoted text, click to view] "Rich" wrote: > slight modification in my setup. I added an additional field to give the > rows some uniqueness. > > CREATE TABLE #tmpA(fname varchar(10), code varchar(1)) > CREATE TABLE #tmpB1(fname varchar(10), code varchar(1)) > CREATE TABLE #tmpB2(fname varchar(10), code varchar(1)) > > INSERT INTO #tmpA > SELECT 'bill', 'A' > UNION ALL SELECT 'tim', 'A' > UNION ALL SELECT 'sue', 'A' > UNION ALL SELECT 'tom', 'A' > UNION ALL SELECT 'bob', 'A' > UNION ALL SELECT 'steve', 'A' > UNION ALL SELECT 'bill', 'B' > UNION ALL SELECT 'tim', 'B' > UNION ALL SELECT 'sue', 'B' > UNION ALL SELECT 'bob', 'B' > UNION ALL SELECT 'bill', 'C' > UNION ALL SELECT 'tim', 'C' > UNION ALL SELECT 'sue', 'C' > UNION ALL SELECT 'bob', 'C' > > INSERT INTO #tmpB1 > SELECT 'bill', 'A' > UNION ALL SELECT 'bill', 'B' > > INSERT INTO #tmpB2 > SELECT 'tim', 'A' > UNION ALL SELECT 'sue', 'A' > UNION ALL SELECT 'tom', 'A' > UNION ALL SELECT 'bob', 'A' > UNION ALL SELECT 'steve', 'A' > UNION ALL SELECT 'tim', 'B' > UNION ALL SELECT 'sue', 'B' > UNION ALL SELECT 'bill', 'C' > UNION ALL SELECT 'tim', 'C' > UNION ALL SELECT 'sue', 'C' > UNION ALL SELECT 'bob', 'C' > > experiment: > > SELECT t1.* FROM #tmpa t1 join > (select * FROM #tmpB1 WHERE fname = 'bill' AND code = 'A' > UNION all > SELECT * FROM #tmpB2 WHERE fname = 'bill' AND code = 'A') t2 > ON t1.code = t2.code > where t1.code = 'A' > > still can't get the counts though
Thank you. your solutions worked great! May I ask what is the difference between an outer join and an inner join? I can understand the left join - pull everything from the left table and only the records that match from the right table. The inner join only pulls records that match from both tables. it looks like an outer join does not have join fields or you are just matching all the fields but they don't have to be equal? [quoted text, click to view] "Alejandro Mesa" wrote: > Try: > > SELECT > * > FROM > ( > SELECT code, COUNT(*) AS cnt > FROM [#tmpA] > GROUP BY code > ) AS a > LEFT OUTER JOIN > ( > SELECT code, COUNT(*) AS cnt > FROM > ( > SELECT * FROM [#tmpB1] > UNION ALL > SELECT * FROM [#tmpB2] > ) AS t > GROUP BY code > ) AS b > ON a.code = b.code > WHERE > b.code IS NULL > OR a.cnt != b.cnt > GO > > -- OR > > SELECT > * > FROM > ( > SELECT code, COUNT(*) AS cnt > FROM [#tmpA] > GROUP BY code > ) AS a > FULL OUTER JOIN > ( > SELECT code, COUNT(*) AS cnt > FROM > ( > SELECT * FROM [#tmpB1] > UNION ALL > SELECT * FROM [#tmpB2] > ) AS t > GROUP BY code > ) AS b > ON a.code = b.code > WHERE > a.code IS NULL > OR b.code IS NULL > OR a.cnt != b.cnt > GO > > > AMB > > > "Rich" wrote: > > > slight modification in my setup. I added an additional field to give the > > rows some uniqueness. > > > > CREATE TABLE #tmpA(fname varchar(10), code varchar(1)) > > CREATE TABLE #tmpB1(fname varchar(10), code varchar(1)) > > CREATE TABLE #tmpB2(fname varchar(10), code varchar(1)) > > > > INSERT INTO #tmpA > > SELECT 'bill', 'A' > > UNION ALL SELECT 'tim', 'A' > > UNION ALL SELECT 'sue', 'A' > > UNION ALL SELECT 'tom', 'A' > > UNION ALL SELECT 'bob', 'A' > > UNION ALL SELECT 'steve', 'A' > > UNION ALL SELECT 'bill', 'B' > > UNION ALL SELECT 'tim', 'B' > > UNION ALL SELECT 'sue', 'B' > > UNION ALL SELECT 'bob', 'B' > > UNION ALL SELECT 'bill', 'C' > > UNION ALL SELECT 'tim', 'C' > > UNION ALL SELECT 'sue', 'C' > > UNION ALL SELECT 'bob', 'C' > > > > INSERT INTO #tmpB1 > > SELECT 'bill', 'A' > > UNION ALL SELECT 'bill', 'B' > > > > INSERT INTO #tmpB2 > > SELECT 'tim', 'A' > > UNION ALL SELECT 'sue', 'A' > > UNION ALL SELECT 'tom', 'A' > > UNION ALL SELECT 'bob', 'A' > > UNION ALL SELECT 'steve', 'A' > > UNION ALL SELECT 'tim', 'B' > > UNION ALL SELECT 'sue', 'B' > > UNION ALL SELECT 'bill', 'C' > > UNION ALL SELECT 'tim', 'C' > > UNION ALL SELECT 'sue', 'C' > > UNION ALL SELECT 'bob', 'C' > > > > experiment: > > > > SELECT t1.* FROM #tmpa t1 join > > (select * FROM #tmpB1 WHERE fname = 'bill' AND code = 'A' > > UNION all > > SELECT * FROM #tmpB2 WHERE fname = 'bill' AND code = 'A') t2 > > ON t1.code = t2.code > > where t1.code = 'A' > > > > still can't get the counts though
Hi Rich, I guess you are asking about the FULL OUTER JOIN, because there two other OUTER joins, LEFT and RIGHT, but you mentioned knowing about them. The FULL OUTER JOIN bring rows from both sides even if there is no match in the opposite side. Example: declare @t1 table (c1 int) declare @t2 table (c1 int) insert into @t1 values(1) insert into @t1 values(2) insert into @t2 values(2) insert into @t2 values(3) select * from @t1 as a left outer join @t2 as b on a.c1 = b.c1 select * from @t1 as a right outer join @t2 as b on a.c1 = b.c1 select * from @t1 as a full outer join @t2 as b on a.c1 = b.c1 I used it in the previous post, just in case. You did not mention anything about if there could be rows in B1 or B2 that were not in A or rows in A that could not be in B1 union all B2. AMB [quoted text, click to view] "Rich" wrote: > Thank you. your solutions worked great! > > May I ask what is the difference between an outer join and an inner join? > > I can understand the left join - pull everything from the left table and > only the records that match from the right table. The inner join only pulls > records that match from both tables. > > it looks like an outer join does not have join fields or you are just > matching all the fields but they don't have to be equal? > > > "Alejandro Mesa" wrote: > > > Try: > > > > SELECT > > * > > FROM > > ( > > SELECT code, COUNT(*) AS cnt > > FROM [#tmpA] > > GROUP BY code > > ) AS a > > LEFT OUTER JOIN > > ( > > SELECT code, COUNT(*) AS cnt > > FROM > > ( > > SELECT * FROM [#tmpB1] > > UNION ALL > > SELECT * FROM [#tmpB2] > > ) AS t > > GROUP BY code > > ) AS b > > ON a.code = b.code > > WHERE > > b.code IS NULL > > OR a.cnt != b.cnt > > GO > > > > -- OR > > > > SELECT > > * > > FROM > > ( > > SELECT code, COUNT(*) AS cnt > > FROM [#tmpA] > > GROUP BY code > > ) AS a > > FULL OUTER JOIN > > ( > > SELECT code, COUNT(*) AS cnt > > FROM > > ( > > SELECT * FROM [#tmpB1] > > UNION ALL > > SELECT * FROM [#tmpB2] > > ) AS t > > GROUP BY code > > ) AS b > > ON a.code = b.code > > WHERE > > a.code IS NULL > > OR b.code IS NULL > > OR a.cnt != b.cnt > > GO > > > > > > AMB > > > > > > "Rich" wrote: > > > > > slight modification in my setup. I added an additional field to give the > > > rows some uniqueness. > > > > > > CREATE TABLE #tmpA(fname varchar(10), code varchar(1)) > > > CREATE TABLE #tmpB1(fname varchar(10), code varchar(1)) > > > CREATE TABLE #tmpB2(fname varchar(10), code varchar(1)) > > > > > > INSERT INTO #tmpA > > > SELECT 'bill', 'A' > > > UNION ALL SELECT 'tim', 'A' > > > UNION ALL SELECT 'sue', 'A' > > > UNION ALL SELECT 'tom', 'A' > > > UNION ALL SELECT 'bob', 'A' > > > UNION ALL SELECT 'steve', 'A' > > > UNION ALL SELECT 'bill', 'B' > > > UNION ALL SELECT 'tim', 'B' > > > UNION ALL SELECT 'sue', 'B' > > > UNION ALL SELECT 'bob', 'B' > > > UNION ALL SELECT 'bill', 'C' > > > UNION ALL SELECT 'tim', 'C' > > > UNION ALL SELECT 'sue', 'C' > > > UNION ALL SELECT 'bob', 'C' > > > > > > INSERT INTO #tmpB1 > > > SELECT 'bill', 'A' > > > UNION ALL SELECT 'bill', 'B' > > > > > > INSERT INTO #tmpB2 > > > SELECT 'tim', 'A' > > > UNION ALL SELECT 'sue', 'A' > > > UNION ALL SELECT 'tom', 'A' > > > UNION ALL SELECT 'bob', 'A' > > > UNION ALL SELECT 'steve', 'A' > > > UNION ALL SELECT 'tim', 'B' > > > UNION ALL SELECT 'sue', 'B' > > > UNION ALL SELECT 'bill', 'C' > > > UNION ALL SELECT 'tim', 'C' > > > UNION ALL SELECT 'sue', 'C' > > > UNION ALL SELECT 'bob', 'C' > > > > > > experiment: > > > > > > SELECT t1.* FROM #tmpa t1 join > > > (select * FROM #tmpB1 WHERE fname = 'bill' AND code = 'A' > > > UNION all > > > SELECT * FROM #tmpB2 WHERE fname = 'bill' AND code = 'A') t2 > > > ON t1.code = t2.code > > > where t1.code = 'A' > > > > > > still can't get the counts though
[quoted text, click to view] "Rich" <Rich@discussions.microsoft.com> wrote in message news:7BF119DC-FCE5-4856-B1CF-CA455119A38F@microsoft.com... >. > May I ask what is the difference between an outer join and an inner join? >.
How is it when you 'think sets' that you end up with a full outer join? Put simply, there is a disconnect between how users are told to think and the language to support it. This is a simple relational division problem obscured by sql because sql has no algebra to compare one set to another. And when you try to compare two sets in sql you wind up with crazy syntax that compounds the original problem rather than clarifying it. There are two tables involved and a simple comparison is all that should be needed. select (#tmpA group by {code} add {Count() Cnt}) Table A code Cnt ---- --- A 6 B 4 C 4 select (#tmpB1 union #tmpB2) group by {code} add {Count() Cnt} Table B code Cnt ---- --- A 6 B 3 C 4 First find all the rows in table A also in table B. where table A is each individual row of table A. Table A < table B if all the rows in table A are in table B, and there is at least one row in table B that is not in table A. select #tmpA group by {code} add {Count() Cnt} //The rows of Table A where ( //Create a table for each row of table A for a //comparison to table B. table{row{code ThisCode,Cnt ThisCnt}} //Test if the table based on each row of table A is < table B. < //Table B ( #tmpB1 union #tmpB2 group by {code} add {Count() Cnt} {code ThisCode,Cnt ThisCnt} ) ); code Cnt ---- --- A 6 C 4 Negate the '<' between the tables for the non-matching rows (counts) ie. there is a row in table A not in table B and there is at least one row in table B not in table A. select #tmpA group by {code} add {Count() Cnt} where not ( table{row{code ThisCode,Cnt ThisCnt}} < ( #tmpB1 union #tmpB2 group by {code} add {Count() Cnt} {code ThisCode,Cnt ThisCnt} ) ); code Cnt ---- --- B 4 This equivalent to the negation of a ('row' from table A in table B). select #tmpA group by {code} add {Count() Cnt} where not ( row{code ThisCode,Cnt ThisCnt} in ( #tmpB1 union #tmpB2 group by {code} add {Count() Cnt} {code ThisCode,Cnt ThisCnt} ) ); code Cnt ---- --- B 4 Would you think more of these ideas if they came from MS? (It's possible) :-) www.beyondsql.blogspot.com
Don't see what you're looking for? Try a search.
|