How to use 2 instances of the same table - sql

I am wondering how to use 2 instances of the same table in the following example , I know how to do it but I just cant make it work for my task.
I have the following tables :
Agency(id_agency,name)
Space(id_space,address)
Offer(id_agency,id_space)
Task: Find out the address,agency name 1 ,agency name 2 for spaces offered by two different agencies(the combination of 2 agencies is unique).
What I tried:
1)
SELECT ADDRESS,A.NAME,B.NAME
FROM AGENCY A
INNER JOIN OFFER O ON A.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
WHERE S.ID_SPACE=ANY(SELECT S.ID_SPACE FROM AGENCY B
INNER JOIN OFFER O ON B.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
);
2)
SELECT ADDRESS
FROM AGENCY A
INNER JOIN OFFER O ON A.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
INTERSECT
SELECT ADDRESS
FROM AGENCY B
INNER JOIN OFFER O ON B.ID_AGENCY=O.ID_AGENCY
INNER JOIN SPACE S ON O.ID_SPACE=S.ID_SPACE
WHERE A.ID_AGENCY<>B.ID_AGENCY;
In the second example I have no idea how to make it show A.name and b.name, since intersect won't work if I try to add them...
I tried to do this for the last 3 hours , sadly, I guess I can`t do it with the skills I have so far. :(
Thanks in advance
Edit 1: I hope you understand, thats how it should look.
Agency
id_agency name
---------- -------
1 Agency1
2 Agency2
3 Agency3
Space
id_space address
--------- --------
1 address1
2 address2
3 address3
Offer
id_agency id_space
----------- --------
1 1
2 1
3 2
Expected output:
Address Name1 Name2
----------- -------- -------
address1 Agency1 Agency2

To have the results in 1 row, each pair of agencies per row, as you asked for:
select S.address as address, A1.name as agency_1, A2.name as agency_2
from offer O1
join offer O2
on O2.id_space = O1.id_space
and O2.id_agency != O1.id_agency
join space S
on S.id_space = O1.id_space
join agency A1
on A1.id_agency = O1.id_agency
join agency A2
on A2.id_agency = O2.id_agency
;
The "core functionality" here is the join of offer no.1 (O1 alias) to offer no.2 (O2 alias) on equality of id_space but difference of id_agency.
An interesting exercise: To have the results in multiple rows, one agency per row:
select S.address, A.name as agency, X.number_of_agencies_per_space
from (
select id_space, id_agency, count(1) over (partition by id_space) as number_of_agencies_per_space
from offer
) X
join space S
on S.id_space = X.id_space
join agency A
on A.id_agency = X.id_agency
where X.number_of_agencies_per_space > 1
;

Related

Most popular pairs of shops for workers from each company

I've got 2 tables, one with sales and one with companies:
Sales Table
Transaction_Id Shop_id Sale_date Client_ID
92356 24234 11.09.2018 12356
92345 32121 11.09.2018 32121
94323 24321 11.09.2018 21231
94278 45321 11.09.2018 42123
Company table
Client_ID Company_name
12345 ABC
13322 ABC
32321 BCD
22221 BCD
What I want to achieve is distinct count of Clients from each Company for each pair of shops(Clients who had at least 1 transaction in both of shops) :
Shop_Id_1 Shop_id_2 Company_name Count(distinct Client_id)
12356 12345 ABC 31
12345 14278 ABC 23
14323 12345 BCD 32
14278 12345 BCD 43
I think that I have to use self join, but my queries even with filter for one week is killing DB, any thoughts on that? I'm using Microsoft SQL server 2012.
Thanks
I think this is a self-join and aggregation, with a twist. The twist is that you want to include the company in each sales record, so it can be used in the self-join:
with sc as (
select s.*, c.company_name
from sales s join
companies c
on s.client_id = c.client_id
)
select sc1.shop_id, sc2.shop_id, sc1.company_name, count(distinct sc1.client_id)
from sc sc1 join
sc sc2
on sc1.client_id = sc2.client_id and
sc1.company_name = sc2.company_name
group by sc1.shop_id, sc2.shop_id, sc1.company_name;
I think there are some issues with your question. I interpreted it as such that the company table contains the shop ID's, not the ClienId's.
First you can create a solution to get the shops as rows for each company. Here I chose a maximum of 5 shops per company. Don't forget the semicolon in the previous statement before the cte's.
WITH CTE_Comp AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY CompanyName ORDER BY ShopID) AS RowNumb
FROM Company AS C
)
SELECT C1.ShopID,
C2.ShopID AS ShopID_2,
C3.ShopID AS ShopID_3,
C4.ShopID AS ShopID_4,
C5.ShopID AS ShopID_5,
C1.CompanyName
INTO ShopsByCompany
FROM CTE_Comp AS C1
LEFT JOIN CTE_Comp AS C2 ON C1.CompanyName= C2.CompanyName AND RowNumb = 2
LEFT JOIN CTE_Comp AS C2 ON C1.CompanyName= C3.CompanyName AND RowNumb = 3
LEFT JOIN CTE_Comp AS C2 ON C1.CompanyName= C4.CompanyName AND RowNumb = 4
LEFT JOIN CTE_Comp AS C2 ON C1.CompanyName= C5.CompanyName AND RowNumb = 5
WHERE C1.RowNumb = 1
After that, in a few steps, I think you could get the desired result:
WITH ClientsPerShop AS
(
SELECT ShopID,
COUNT (DISTINCT ClientID) AS TotalClients
FROM Sales
GROUP BY ShopID
)
, ClienstsPerCompany AS
(
SELECT CompanyName,
SUM (TotalClients) AS ClientsPerComp
FROM Company AS C
INNER JOIN ClientsPerShop AS CPS ON C.ShopID = CPS.ShopID
GROUP BY CompanyName
)
SELECT *
FROM ClienstsPerCompany AS CPA
INNER JOIN ShopsByCompany AS SBC ON SBC.CompanyName = CPA.CompanyName
Hopefully this will bring you closer to your solution, best of luck!

grabbing information by joining multiple tables

This is going to be a little complicated. Let me start with my tables.
clients [src = 0]
---------
clientID code company
--------- ------- ---------
1 ABC ABC Corp
2 DEF DEF Corp
carriers [src = 1]
---------
clientID code company
--------- ------- -------
1 ABC ABC Inc.
2 JHI JHI Inc.
link
--------
contactID uID src
--------- ----- ----
1 1 0
1 1 1
1 2 0
contact info
--------------
contactID fname lname
--------- ------- --------
1 John Smith
2 Quincy Jones
So, i'm trying to do a search for say "ABC" on the link table. The link table needs to basically join to either the carriers or clients table depending on the link.src column. It should find two matches, one in the clients and one in the carriers, but since both resolve to contactID (links table) of 1, i should then query the contact info table and return
Found 1 record(s):
John Smith
I hope this makes sense. Any help is greatly appreciated!
Here is one approach using left join:
select co.*
from link l left join
clients cl
on l.src = 0 and l.uid = cl.code left join
carriers ca
on l.src = 1 and l.uid = ca.code left join
contacts co
on l.contactid = co.contactid
where 'ABC' in (co.code, cl.code)
Here is another approach. First, you UNION the Clients and Carriers tables and add a new column ContactType to differentiate one from the other. Use 0 for Clients and 1 for Carriers, the same as src. Then you perform a LEFT JOIN to get the desired result.
;WITH Clients(ClientID, Code, Company) AS(
SELECT 1, 'ABC', 'ABC Corp' UNION ALL
SELECT 2, 'DEF', 'DEF Corp'
)
,Carriers(ClientID, Code, Company) AS(
SELECT 1, 'ABC', 'ABC Inc.' UNION ALL
SELECT 2, 'JHI', 'JHI Inc.'
)
,Link(ContactId, UID, Src) AS(
SELECT 1, 1, 0 UNION ALL
SELECT 1, 1, 1 UNION ALL
SELECT 1, 2, 0
)
,ContactInfo(ContactID, FName, LName) AS(
SELECT 1, 'John', 'Smith' UNION ALL
SELECT 2, 'Quincy', 'Jones'
)
-- START
,Contact(ContactID, ContactType, Code, Company) AS(
SELECT
ClientID, 0, Code, Company
FROM Clients
UNION ALL
SELECT
ClientID, 1, Code, Company
FROM Carriers
)
SELECT DISTINCT
ci.FName,
ci.LName
FROM Link l
LEFT JOIN Contact c
ON c.ContactID = l.UID
AND c.ContactType = l.src
LEFT JOIN ContactInfo ci
ON ci.ContactID = c.ContactID
WHERE
c.Code = 'ABC'
Look at this from a modeling pov. You have two tables with the same type of data in each one, the entity company. The only difference between them is their role or relationship to your company. So why not keep them all in the same bucket?
Companies:
ID code Name
-- ---- ---------
1 ABC ABC Corp
2 DEF DEF Corp
3 JHI JHI Inc.
If a particular company could only be a client or a carrier, that designation could be placed in the Companies table. Since obviously one company can be both, the designation goes into a separate table. The following shows that company 1, 'ABC', is both a client ('L') and carrier ('R'), company 2 is only a client and company 3 is only a carrier.
CompanyRoles:
CompanyID Type
--------- ----
1 'L'
1 'R'
2 'L'
3 'R'
There is no need to keep multiple copies of the same data just because a company can play multiple roles. If there is role-dependent data, data that is maintained on client but not for carriers, or vice versa, then subtables can keep that.
As for the contacts, if a company has one contact no matter the role, the contact reference can be added to the Companies table. If the contact is role dependent, it is added to the CompanyRoles table.
CompanyRoles:
CompanyID Type ContactID
--------- ---- ---------
1 'L' 1
1 'R' 2
2 'L' 3
3 'R' 4
Want to see a list of clients?
select c.ID as ClientID, c.Code as ClientCode, c.Name as ClientName,
ci.ContactName
from Companies c
join CompanyRoles cr
on cr.CompanyID = c.ID
and cr.Type = 'L'
left join Contacts ct -- In case no contact is currently defined
on ct.ContactID = cr.ContactID
join ClientSpecificData csd
on csd.ClientID = c.ID;
Want to see a list of carriers?
select c.ID as CarrierID, c.Code as CarrierCode, c.Name as CarrierName,
ci.ContactName
from Companies c
join CompanyRoles cr
on cr.CompanyID = c.ID
and cr.Type = 'R'
left join Contacts ct -- In case no contact is currently defined
on ct.ContactID = cr.ContactID
join CarrierSpecificData csd
on csd.ClientID = c.ID;
You can create views on the last two queries to provide a single data source for those apps that deal with only Clients or only Carriers. Triggers on the views can deal with incoming DML statements as needed to route the data to the appropriate tables.
As you can see, the queries are clean and simple. Data integrity is easy and scalability is not an issue. What more could you want?

Get data from relational tables

I have following tables in my db.
Calls:
ID Name
1 Call1
2 Call2
3 Call3
Notes:
ID Name
1 Note 1
2 Note 2
Person:
ID Name
1 Andrew
PersonCalls:
ID CallID PersonID
1 1 1
2 2 1
PersonNotes:
ID NoteID PersonID
1 1 1
1 2 1
Now I need to get data from these tables according to person id. I am able to get data from 2 tables, for example Notes and PersonNotes, but I am not able to get combined data from these tables. This should be the result.
Result:
PersonID Note Call
1 Note1 Call1
1 Note2 Call2
Please suggest
Thanks
Use Join (ie: Inner Join):
select distinct p.ID as PersonID, n.Name as Note, c.Name as Call from Person p
inner join PersonCalls pc on p.ID = pc.PersonID
inner join PersonNotes pn on p.ID = pn.PersonID
inner join Calls c on pc.CallID = c.ID
inner join Notes n on pn.NoteID = n.ID
Without getting too detailed you can use a left join on dbo.calls.ID, dbo.notes.id, dbo.person.id, etc if you are using MS SQL server. Otherwise are you sure you can't just write a report?

Left Outer Join with one result per match and "priority" of match set by a different field in match SQL Server 2005

I am trying to get a single result (PHONE) per match (CONTACT_ID) in a Left Outer Join. I imagine that there is a way to accomplish this with the preference (or order) being set by another column/field- the phone type (TYPE), but I haven't been able to figure it out. Below is a list of facts to help better explain what I am trying to accomplish and then following is an example Table A and B with the desired result. I've looked at min() and group by, but I don't know how to make those work here. As a side note, after this is working, I will be joining it to more tables to the left of it in a simpler fashion.
The student can have an unlimited number of CONTACT_ID.
A contact does not always have all phone types.
The preferred order of phone types (TYPE) is C,H,W (which, fortunately, happens to be alphabetical)
ignore match and go to the next in priority if PHONE is null
TableA:
STUDENT_ID CONTACT_ID
---------- ----------
X 1
X 2
Y 3
Y 4
TableB:
CONTACT_ID TYPE PHONE
---------- ---- -----
1 H 21
1 C
1 W 44
2 H 78
2 C 92
2 W 11
Desired Result:
STUDENT_ID CONTACT_ID TYPE PHONE
---------- ---------- ---- -----
X 1 H 21
X 2 C 92
Y 3
Y 4
Here is the query that I have that will make a join with all phone matches (minus all of my crazy attempts at getting what I want).
SELECT *
FROM Table TableA T1
LEFT OUTER JOIN TableB T2 ON T1.CONTACT_ID = T2.CONTACT_ID
All help greatly appreciated!
Edited code from Stefan Onofrei's solution:
(results in some duplicate entries)
SELECT
T1.STUDENT_ID,
T1.CONTACT_ID,
T2.PHONE_TYPE,
T3.PHONE
FROM REG_STU_CONTACT T1
INNER JOIN
(SELECT MIN(PHONE_TYPE) AS PHONE_TYPE, CONTACT_ID
FROM REG_CONTACT_PHONE
WHERE PHONE IS NOT NULL
GROUP BY CONTACT_ID) T2 ON T1.CONTACT_ID = T2.CONTACT_ID
INNER JOIN REG_CONTACT_PHONE T3 ON T2.CONTACT_ID = T3.CONTACT_ID AND T2.PHONE_TYPE = T3.PHONE_TYPE
ORDER BY T1.STUDENT_ID
Select A.STUDENT_ID A.CONTACT_ID B.TYPE c.PHONE
from TableA A
inner join
(select MIN(type ) as type, Contact_ID
from Tableb
where phone is not null
group by contactid) B
on A.contactid = b.contactid
inner join Tableb C
on B.contactid = c.conatctid and b.type = c.type

SQL query: need help on subquery

Question is as follows:
There are 2 related tables (am giving some sample values for making it simplified):
Circuit
--------
id name
1 a
2 b
3 c
Circuit_Dependent
-----------------
id depend_id
1 2
1 3
the tables are related and second table tells the relation with the circuit id's.
Situation is query needed for:
1) list the circuit name which has the circuit_dependency
output expected:
name dependent_name
a b
a c
2) list the circuit name and count(no of dependancies)
output expected:
name count
a 2
appreciate help.
First query could be:
SELECT c1.`name`, c2.`name`
FROM Circuit_Dependent cd INNER JOIN Circuit c1
ON cd.id = c1.id
INNER JOIN Circuit c2
ON cd.depend_id = c2.id
Second query could be this one:
SELECT c.`name`, COUNT(DISTINCT cd.depend_id) AS count
FROM circuit c INNER JOIN Circuit_Dependent cd
ON c.id = cd.id
GROUP BY c.id