Can anyone tell me, how inner join works in SQL? - sql

I have a table A and B, both has one column and two rows as follows,
A B
-------
C1 C2
1 1
1 1
1 0
0 0
If I apply a inner join on this and the it is returning 8 rows as a results,
Select C1,C2 from A inner join B on A.C1=B.C2;
Result
---------
C1 C2
1 1
1 1
1 1
1 1
1 1
1 1
0 0
0 0
And I am guessing that, first row of the C1 column is checking with the data of all C2 columns. If it's matches, its returning result otherwise, it won't. The same method was following for the rest of the columns. Correct me, if my understanding was wrong and please assist with the answer for the below question;
I have two tables A,B both are having two columns. What will be the result if we apply inner join, please explain me with functionality.
A B
----–-----------
C1 C2 C3 C4
1 1 1 1
1 1 1 0
Select C1,C2,C3,C4 from A inner join B on A.C1=B.C3;
It's returning 4 rows, please explain how?

This is common misconception about inner joins. Concept of inner join says a value in a column of a table will match with each and every occurrence of same value of joining column in another table.
In your example, in table A First row of 1 of column C1 will match with all 2 rows of value 1 of column C2 of table B, Second 1 will match with all 2 1's then 3rd 1 will match with all 2 of able B. Then a 0 will match 2 times in table B.
Thus they becomes - 2(1's) + 2(1's) + 2(1's) + 2(0's) = 8 rows.
Same concept applies to your second example as well. Since you have 2 columns in your 2nd example, So you have to decide the join predicate here.
If you decided to join like `A.C1 = B.C3` then 4 rows will occur in result.
If you decided to join like `A.C1 = B.C4` then 2 rows will occur in result.
If you decided to join like `A.C2 = B.C3` then 4 rows will occur in result.
If you decided to join like `A.C2 = B.C4` then 2 rows will occur in result.

In your example, if you use the predicate A.C1 = B.C3 the result is:
c1 c2 c3 c4
--- --- --- --
1 1 1 1
1 1 1 1
1 1 1 0
1 1 1 0
See running example at DB Fiddle.
Now, as a general rule, the inner join will match rows from both tables according to any predicate you specify, not necessarily simple column values.
For example:
A B
-------- --------
C1 C2 # C3 C4 #
1 1 A1 1 1 B1
1 1 A2 1 0 B2
0 1 B3
If the predicate is a.c1 * a.c2 = b.c3 + b.c4, as in the query:
select
a.*,
b.*
from a
join b on a.c1 * a.c2 = b.c3 + b.c4
The result is:
c1 c2 c3 c4 matching predicate
--- --- --- -- --------------------------
1 1 1 0 1 * 1 = 1 + 0 (A1 and B2)
1 1 1 0 1 * 1 = 1 + 0 (A2 and B2)
1 1 0 1 1 * 1 = 0 + 1 (A1 and B3)
1 1 0 1 1 * 1 = 0 + 1 (A2 and B3)
Do you see how the rows are matched?

Related

Excluding Certain Matching Rows in an SQL Join

My issue somewhat complex, so I will explain using simplified versions of my tables.
This is Table 1:
Value L AID OID
A 1 1
B 2 1
C 3 1
D 4 1
E 2 1
F 2 2
G 2 3
H 2 4
This is Table 2:
Value R AID OID VAR
Z 0 1 0
Y 1 1 1
X 2 1 1
W 4 1 1
V 0 2 0
U 1 2 1
T 3 2 1
I would like to join these tables such that any row in Table 1 that doesn’t have a corresponding row in Table 2 with both matching AID and OID is returned in a join to the row with a matching OID and an AID and VAR of 0. In this example it would look like this:
Value L Value R AID OID VAR
C Z 3 1 0
F V 2 2 0
H V 4 2 0
I am not certain how to tackle this. Specifically, not sure how to stop the rows that have a matching AID and OID from showing up in my join, and only having the rows that don't have that match. Any advice would be appreciated.
I think you want not exists:
select t1.*
from table1 t1
where not exists (select 1
from table2 t2
where t2.aid = t1.aid and t2.oid = t1.oid and t2.var = 0
);

Case for the whole dataset in sql table

Have a table like that. Let's pretend it is full table and we dont have any other rows:
ID Place
1 A
1 B
2 C
3 D
How can I perform such thing:
ID Place YesNo
1 A 1
1 B 1
1 C 0
1 D 0
2 A 0
2 B 0
2 C 1
2 D 0
3 A 0
3 B 0
3 C 0
3 D 1
For yes/no I need CASE statement but how to do the rest- full join table on itlself or some other options?
Thanks!
You can achieve that with two subqueries which each list the possible values of one of the columns. The two results should then be crossed to get all combinations. Finally outer join this with the original table to see which combinations actually occur:
SELECT first.ID,
second.Place,
CASE WHEN mytable.ID IS NULL THEN 0 ELSE 1 END AS YesNo
FROM (
SELECT DISTINCT ID
FROM mytable
) first
CROSS JOIN (
SELECT DISTINCT Place
FROM mytable
) second
LEFT JOIN mytable
ON mytable.ID = first.ID
AND mytable.Place = second.Place
ORDER BY first.ID,
second.Place
Here is an SQL fiddle

Hiding a row where value = 0 but count its other column values in total calculations - sql2008

I have tables like that: (C1-C2 varchar(10), C3-Number int)
WaitingData
C1 C2 C3 Number
A B 1 10
A B 2 0
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
A B 3 0
X B 4 12
I am using the query below to represent the data:
Select wd.C1,wd.C2,wd.C3,wd.Number as NW,cdd.Number as NC
into #AllData
from (Select C1,C2,C3,sum(Number) from WaitingData group by C1,C2,C3) wd
outer apply (Select C1,C2,C3,sum(Number)
from CompletedData cd
where wd.C1=cd.C1 and wd.C2=cd.C2 and wd.C3=cd.C3
) cdd
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NW)
from #AllData
This is giving me an output like:
C1 C2 C3 NW NC
A B 1 10 5
A B 2 0 2
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
However, I want to hide the rows that has no NW but calculate its regarding values while calculating the Total row (see NC below). The output I want is like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 0
X B 4 2 12
Total Total -1 16 19
I could not find a way to provide an output like this. Any help would be so appreciated!
------------------------------EDIT---------------------------------------
------------------------------EDIT---------------------------------------
When I have data in the tables like below, the outer apply is not working like I want, it does not include the data A B 2.
WaitingData
C1 C2 C3 Number
A B 1 10
A B 3 4
X B 4 2
CompletedData
C1 C2 C3 Number
A B 1 5
A B 2 2
X B 4 12
And the output would be like:
C1 C2 C3 NW NC
A B 1 10 5
A B 3 4 NULL
X B 4 2 12
Total Total -1 16 17
In this situation, what can I do to count "2" NC value having by A B 2 on the final result and see NC as 19 instead 17, except inserting all the records that included by CompletedData but WaitingData? (need an efficient way)
Wrap the final result with one more select and exclude rows where NW = 0.
select * from
(
Select * from #AllData
union
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from #AllData
) t
where NW <> 0
Edit: Using a full join to get all values from both tables.
with t as
(select coalesce(w.c1,c.c1) as c1,coalesce(w.c2,c.c2) as c2,coalesce(w.c3,c.c3) as c3
, coalesce(w.number,0) as nw , coalesce(c.number,0) as nc
from waitingdata w
full join completeddata c on w.c1 = c.c1 and w.c2=c.c2 and w.c3=c.c3)
select * from
(select * from t
union all
Select C1='Total',C2='Total',C3=-1, sum(NW),sum(NC)
from t) x where nw <> 0
You can do all of this in one query, without temporary tables, intermediate results, subqueries, or UNION by using the ROLLUP operator:
SELECT
WD.C1,
WD.C2,
WD.C3,
SUM(WD.Number) AS NW,
SUM(CD.Number) AS NC
FROM
dbo.WaitingData WD
LEFT OUTER JOIN CompletedData CD ON
CD.C1 = WD.C1 AND
CD.C2 = WD.C2 AND
CD.C3 = WD.C3
GROUP BY
WD.C1,
WD.C2,
WD.C3
WITH ROLLUP
HAVING
GROUPING_ID(WD.C1, WD.C2, WD.C3) IN (0, 7) AND
SUM(WD.Number) <> 0

Why left join returns same output as cartesian join if the column values are equal

If I have 2 tables, each table has one column only:
Table A:
col1
1
1
1
Table B:
col1
1
1
1
When I say:
select * from A left join B on a.col1 = b.col1
It has same output as :
select * from A,B (cartesian join).
Why is this?
If you add another column for clarity's sake, I think the answer becomes easier to visualise:
Table A:
ID col1
1 1
2 1
3 1
Table B:
ID col1
1 1
2 1
3 1
So your cartesian product is:
A.ID A.Col1 B.ID B.ID
1 1 1 1
1 1 2 1
1 1 3 1
2 1 1 1
2 1 2 1
2 1 3 1
3 1 1 1
3 1 2 1
3 1 3 1
Now add the predicate WHERE A.Col1 = B.Col1 and you can see that this is true for all the rows. So a left join will return the same results as a cross join.

SELECT statement with multiple WHERE criteria (MS-Access)

Below is the sample data:
c1 c2 c3 c4 c5
1 a1 a 1 1
2 a2 a 2 1
3 a3 a 3 1
4 a4 a 4 1
5 b1 b 1 1
6 b2 b 2 1
7 b3 b 3 1
8 b4 b 4 1
9 a1 c 3 1
I want to get the the below details:
c1 c2 c3 c4 c5
1 a1 a 1 1
5 b1 b 1 1
9 a1 c 3 1
C1 is primary key, the criteria is for any given unique(c2) where c4 is the lowest, I want to return the contents(all the 5 columns) of the row.
Try this:
SELECT t1.*
FROM Table1 t1
INNER JOIN
(
SELECT c3, MIN(c4) c4
FROM Table1
GROUP BY c3
) t2 ON t1.c3 = t2.c3 ANd t1.c4 = t2.c4
SQL Fiddle Demo
Update:1 In SQL the returned results is a set set(unless you specify an ORDER BY clause, it is a cursor in this case), wherein the order is not guaranteed. This is a standard. You should use an ORDER BY clause if you want to guarantee a specific order. In your case , the results is not guaranteed to be ordered like 1 5 9. Add ORDER BY c1 instead.
The ORDER BY clause might be crucial in some cases, for example, if want to get the top three rows, or the maximum one, in this case you have to specify an ORDER BY clause.
So if you wants to persist a specific order the you have specify an ORDER BY.
1 As noted by #Fahim Parker, see the comments below.
select c1,c2,c3,c4,c5
from table
where c4= (select min(c4) from table as f where f.c4 = table.c4);
i hope that helps