Creating a VIEW to get a connection count - sql

I have a table below which stores Connections between 2 person
TABLE (CONNECTION)
ID | REQUEST_PERSON | REQUESTEE_PERSON
I would like to build a VIEW which gets the REQUEST_PERSON, REQUESTEE_PERSON and MUTUAL_CONNECTION_COUNT(other common connections count between them). Any help is appreciated
For Example if we have a table data as below
ID | REQUEST_PERSON | REQUESTEE_PERSON
1 A B
2 A C
3 B C
4 D B
5 D A
6 A E
7 B E
8 A F
9 C G
I need a VIEW display below
ID | REQUEST_PERSON | REQUESTEE_PERSON | MUTUAL_CONNECTION_COUNT
1 A B 3
2 A C 1
3 B C 1
4 D B 1
5 D A 1
6 A E 1
7 B E 1
8 A F 0
9 C G 0

This is rather tricky. Here is code that does what you want:
select c.*,
(select count(*)
from (select v.person2
from connections c2 cross apply
(values (c2.REQUESTEE_PERSON, c2.REQUEST_PERSON), (c2.REQUEST_PERSON, c2.REQUESTEE_PERSON)
) v(person1, person2)
where v.person1 IN (c.Request_Person, c.Requestee_Person)
group by v.person2
having count(*) = 2
) v
) in_common
from connections c
order by id;
Here is a SQL Fiddle.
The essence of the problem is finding people who are connected to both people in each row. Your connections are unidirectional, which makes the logic hard to express -- C could be either the first or second person in either connection.
Arrgh!
So, the innermost subquery adds reverse links to the graph. Then, it can focus on filtering by the first person -- who has to match the persons in the outer query. The second person is the one that might be in common.
The inner aggregation is just summarizing by the second person. It filters using having count(*) = 2 to indicate that both people in the outer query need to be connected to the second person in the inner query. The count(*) assumes that you have no duplicates.
Then, these are counted, which is the value you want.

Related

Filling the NULL parts of the tabels in the left join

I have two tables that have similar structure but I need to obtain all information relative to zip code.
tableA
zip_code location
1 A
2 C
2 D
3 E
4 F
5 G
tableB
zip_code location n
2 A 1
2 C 2
2 D 3
3 A 4
3 E 5
4 F 6
4 H 7
6 Y 8
As you can see, one locatıon can have multiple zip_code. So, I have to use zip_code and location for the join condition. When I applied left join, I couldn't manage to fill NULL parts. My strategy to fill it is like this:
If zip_code in the tableA is not in the tableB, I search for the location names and choose the n based on the minimum difference between zip_codes.
If zip_code and location in the tableA are not in the tableB, I want to search for n based on the minimum difference between zip_codes, and if there are multiple possibilities based on this I want to choose the minimum n.
NOTE: When looking at the difference between zip_codes, if there is a situation where they are equal I want to get the smaller number. For example, 5 could get 4 and 6 in terms of minimum difference but I want to go with 4 and look other conditions then.
The resulting table should be something like this:
zip_code location n
1 A 1
2 C 2
2 D 3
3 E 5
4 F 6
5 G 6
I know it is a bit complicated but I can explain the fuzzy parts with more details
This sounds like an OUTER APPLY:
select a.*, b.n
from tableA a outer apply
(select top (1) b.*
from tableB b
order by (case when b.zip_code = a.zip_code and b.location = a.location
then -1
when b.location = a.location
then abs(b.zip_code - a.zip_code)
else abs(b.zip_code - a.zip_code)
end),
b.n
) b;
Here is a db<>fiddle.

working of the left join

I have an example where in a table there is ID,NAme and M_if(managerID). I populated the table in the following manner
Id Name M_id
1 A 2
2 B NUll
3 C 1
4 D 3
5 E 2
Id is employee ID, Name and M_id is manager ID. In above example A's manager is 2(B), B doesn't have manager, C's manager is 1(A) and so on. I need to find out the names of the employees and their managers name. I have written the following query by doing permutations and combinations which gives me proper result but I am not able to comprehend how exactly the query(left join) is working. Please make me explain the concept.
SELECT (e.Name), ee.name FROM test.employee e
left join test.employee ee on ee.Id = e.M_id
order by e.Id;
result i get
A B
B
C A
D C
E B
Please explain me the joint
two instances are there for same table as :
e
Id Name M_id
1 A 2
2 B NUll
3 C 1
4 D 3
5 E 2
ee
Id Name M_id
1 A 2
2 B NUll
3 C 1
4 D 3
5 E 2
according to your join condition on ee.Id = e.M_id
simply first row of instance e will be selected because of left join and e.M_id will get compared to ee.Id and 2nd row will be selected from second instance of same table.
selection of data from both the table is as :
e.Id e.Name e.M_id | ee.Id ee.Name ee.M_id
1 A 2 | 2 B NUll
2 B NUll |
3 C 1 | 1 A 2
4 D 3 | 3 C 1
5 E 2 | 2 B NUll
that is why it is showing
A B

Using multiple joins (e.g left join)

I would like to know what's the logic for multiple joins (for example below)
SELECT * FROM B returns 100 rows
SELECT B.* FROM B LEFT JOIN C ON B.ID = C.ID returns 120 rows
As I know using left join will returns any matching data from the left table which is B if data are found for both table. But how come when using left join, it returns more data than table B itself?
What am I do wrong or misunderstood here? Any guidance are very appreciated. Thanks in advance.
Let be table B:
id
----
1
2
3
Let be table C
id name
------------
1 John
2 Mary
2 Anne
3 Stef
Any id from b is matched with ids from c, then id=2 will be matched twice. So a left join on id will return 4 rows even if base table B has 3 rows.
Now look at a more evil example:
Table B
id
----
1
2
2
3
4
table C
id name
------------
1 John
2 Mary
2 Anne
3 Stef
Every id from b is matched with ids from c, then first id=2 will be matched twice and second id=2 will be matched twice so the result of
select b.id, c.name
from b left join c on (b.id = c.id)
will be
id name
------------
1 John
2 Mary
2 Mary
2 Anne
2 Anne
3 Stef
4 (null)
The id=4 is not matched but appears in the result because is a left join.
Look at the following example :
B = {1,2}
C = {(1,a),(1,b),(1,c),(1,d),(1,e)}
The result of B left join C will be :
1 | a
1 | b
1 | c
1 | d
1 | e
2 | null
The number of rows in the result is definitely larger than rows in B (2).
In general the number of rows in result of B left join C is bounded by B.size + C.size and not only by B.size as you think...
As per your query it do the join to B Table with C and B table is Left Table so it will display all the records of Left table in our case it is B and related from other Table in our Case it is C.

comparing rows in sql on two different columns

id address retailer
1 A 11
2 A 11
3 A 11
4 A 12
5 A 13
6 B 12
7 B 12
8 B 13
My output should be
id address retailer
1 A 11
4 A 12
5 A 13
6 B 12
8 B 13
i.e my query should return id's which have same address but not same retailer.
How toget this?
Try to use group by clause as below:
select min(id), address, retailer
from tab
group by address, retailer
Assuming you're joining on columns with no duplicates, which is by far the most common case:
An inner join of A and B gives the result of A intersect B, i.e. the inner part of a venn diagram intersection.
An outer join of A and B gives the results of A union B, i.e. the outer parts of a venn diagram union.
Examples:
Suppose you have two Tables, with a single column each, and data as follows:
A B
- -
1 3
2 4
3 5
4 6
Note that (1,2) are unique to A, (3,4) are common, and (5,6) are unique to B.
Inner join:
An inner join using either of the equivalent queries gives the intersection of the two tables, i.e. the two rows they have in common.
select *
from a
INNER JOIN b on a.a = b.b;
select a.*,b.*
from a,b
where a.a = b.b;
a | b
--+--
3 | 3
4 | 4
Left outer join:
A left outer join will give all rows in A, plus any common rows in B.
select *
from a
LEFT OUTER JOIN b on a.a = b.b;
select a.*,b.*
from a,b
where a.a = b.b(+);
a | b
--+-----
1 | null
2 | null
3 | 3
4 | 4
Full outer join:
A full outer join will give you the union of A and B, i.e. All the rows in A and all the rows in B. If something in A doesn't have a corresponding datum in B, then the B portion is null, and vice versa.
select *
from a
FULL OUTER JOIN b on a.a = b.b;
a | b
-----+-----
1 | null
2 | null
3 | 3
4 | 4
null | 6
null | 5
select min(id) as id,address, retailer
from table1
group by address, retailer
order by id
The query you need is:
SELECT min(id), address, retailer
FROM table1 AS t1
group by address, retailer
order by address
Here's the source
Use This: It's working:
SELECT * FROM `sampletable` GROUP BY address, retailer

SQL one to one mapping with select query only

I have two table with name LeftTable and RightTable as below
LeftTable
obsid Name Value
1 Ronak A
2 Aakash B
3 Pankti C
4 Sanket D
RightTable
obsid Name Value
1 Jhone F
2 Isabella M
3 Jonathan L
4 javafx p
Now when I Left join in some condition the output will be as below
ResultTable
obsid Name Value obsid Name Value
-------------------------------------------------------------------------
1 Ronak A 1 Jhone F
1 Ronak A 2 Isabella M
1 Ronak A 3 Jonathan L
1 Ronak A 4 javafx p
2 Aakash B 2 Isabella M
2 Aakash B 3 Jonathan L
2 Aakash B 4 javafx p
3 Pankti C 3 Jonathan L
3 Pankti C 4 javafx p
4 Sanket D 4 javafx p
This Left Join is help me to achieve One-To-Many Relationship in my application.
Left join condition is dynamic in my application. so its just an example I shown here. Suppose Left Join condition in above exampple is LeftTable.Obsid <= RightTable.Obsid
Now I want to achieve One-To-One relationship.
One-To-One relationship means when any of righttable record linked once with any lefttable record then that righttble record can not be linked with any other lefttable record.
For above example Output for one to one is as below
obsid Name Value obsid Name Value
1 Ronak A 1 Jhone F
2 Aakash B 2 Isabella M
3 Pankti C 3 Jonathan L
4 Sanket D 4 javafx p
I have achieve this functionality two way:
Using cursor
fetching one by one record using select query
Database tables are dynamic in my application. so while processing on millions of record takes too much time as fetching one by one record and processing on it takes time.
Is there any way to achieve One-To-One relation in single select query??
I want to avoid fetching one by one record and I am using Mysql database
Please help me.
You can achieve the required output which is shown in the example by just using inner join.
select * from LeftTable L inner join RightTable R
on L.obsid=R.obsid
But I if there are duplicate obsid in the left table you can use the below query
select A.obsid,A.Name,A.Value, R.obsid,R.Name,R.Value from(
select *,row_number() over (partition by obsid order by obsid ) as row_num
from LeftTable)A
inner join RightTable R
on A.obsid=R.obsid
where A.row_num=1
Please let me know this is what you expect