I have a parent device table, as well as the division table.
In between there are the stops and ctrltab tables, each of which have properties device_id that matches with device, as as pipe_division_id which connects to the pipe_division table.
EDIT: By request I have added sample tables below
Device table
device_id | name | board_number
--------------------------------
23 Stop1 10
24 Stop2 11
25 Ctrltab1 11
26 Rand_dev 8
Stop table
device_id | label | pipe_division_id | length
23 Stop1: Piano 305 16
24 Stop2: Buffet 306 16
Ctrltab table
device_id | label | pipe_division_id | ctrl_function
25 Ctrltab1 305 open_window
Pipe Division table
pipe_division_id | label | position
305 Lower Box underneath the stairs
306 Upper Box above the stairs
307 Side Box To the left of the console in the closet
Expected result of query:
name | board_number | label
Stop1 10 Lower Box
Stop2 11 Upper Box
Ctrltab1 11 Lower Box
Essentially, I would like to select all the devices in the device table with a board number higher than 10, that have a pipe_division_id that is found by connecting their stop or ctrltab tables.
I tried
Select name, board_number, pd.label
from device d
JOIN stops s ON s.device_id = d.device_id
JOIN ctrltab ct ON ct.device_id = d.device_id
JOIN pipe_division_id pd ON (s.pipe_division_id = pd.pipe_division_id
OR ct.pipe_division_id = pd.pipe_division_id)
but this does not bring up any results, I suppose this OR statement is not valid? I would rather avoid a union as the real query is very long and I wouldn't like to repeat all that text just for a minor difference in finding the pipe_division label.
SELECT d.name, d.board_number, COALESCE(pd1.label, pd2.label) AS label
FROM device d
LEFT JOIN stop s ON s.device_id = d.device_id
LEFT JOIN pipe_division pd1 ON s.pipe_division_id = pd1.pipe_division_id
LEFT JOIN ctrltab ct ON ct.device_id = d.device_id
LEFT JOIN pipe_division pd2 ON ct.pipe_division_id = pd2.pipe_division_id
WHERE d.board_number > 10;
Dbfiddle
Related
I have two tables I would like to join.
Table A
Date | Hour | Direction | Qty
2018-11-20 1 DE/UK 2
2018-11-20 2 DE/UK 6
Table B
Date | Hour | Area | Price
2018-11-20 1 DE 5
2018-11-20 2 DE 4
2018-11-20 1 UK 3
2018-11-20 2 UK 9
I want to join them like this:
Table C
Date | Hour | Direction | Qty | AreaFrom | AreaTo | PriceFrom | PriceTo | Profit
2018-11-20 1 DE/UK 2 DE UK 5 3 3-5 = -2
2018-11-20 2 DE/UK 6 DE UK 4 9 5
I have tried by CROSS Join and other kinds of joins, but have not been able to make it work.
Other related questions I have looked at so far:
SQL subtract two rows based on date and another column
Selecting two rows from the same table
It might not be as complex as Adam makes out. If the TableA had a "directionFrom" and a "directionTo" columns you'd probably have worked this out by yourself. So let's cut up the direction field into two columns:
SELECT
a.[Date], a.[Hour], a.Direction, a.Qty,
f.Area as AreaFrom, t.Area as AreaTo,
f.Price as priceFrom, t.Price as PriceTo,
t.Price-f.Price as profit
FROM
TableA a
INNER JOIN TableB f
ON
a.[Date] = f.[Date] and
a.Hour = b.[Hour] and
LEFT(a.Direction, 2) = f.Area --take the left two as the area from
INNER JOIN TableB t
ON
a.[Date] = t.[Date] and
a.Hour = t.[Hour] and
RIGHT(a.Direction, 2) = t.Area --take the right two as the area to
If you ever have areas with more than two letter codes, you'll have to SUBSTRING on the CHARINDEX of the / instead
Tables:
Client
CID Name
1 A
2 B
3 C
4 D
5 E
6..(And so on)
Visit
VID CID type
1 1 Med
2 3 Non
3 2 Non
4 6 Med
5 4 Med
6..(And so on)
Payment
PID CID amount
1 1 10
2 1 20
3 2 30
4 2 40
5 3 50
6..(And so on)
Desired Output:
CID Name type amount
1 A Med 10
1 A Med 20
4 D Med NULL
(And so on..)
Query:
SELECT DISTINCT
C.client_id
,C.name
,V.type
,P.payment
FROM Clients C
INNER JOIN Visit V
ON C.cid=V.cid
LEFT JOIN Payment P
ON V.cid=P.cid
I used a LEFT JOIN because I wanna see who made payments and who didn't.
Question: Do LEFT JOINS (or outer joins) pull in data based on the common id's in the CID of the left table resulting from preceding INNER JOINS(The common result set)? Or do they consider ALL the id's in the left table and ignore the INNER JOINS results altogether?
I only want payment details of the clients existing in the inner joins and not outside it.
The LEFT JOIN will only run on rows that the INNER JOIN returns, or the common data set as you mention.
That is regardless of what the LEFT JOIN will return, the INNER JOIN is going to limit the result set based on Visit V ON C.cid=V.cid
This venn diagram shows the results that will be selected, the blue area is your data that will be returned. The order of the joins does not matter.
I am trying to extract some data grouped by the markets we operate in. The table structure looks like this:
bks:
opportunity_id
bks_opps:
opportunity_id | trip_start | state
bts:
boat_id | package_id
pckgs:
package_id | boat_id
addresses:
addressable_id | district_id
districts:
district_id
What I wanted to do is to count the number of won, lost and total and percentage won for each district.
SELECT d.name AS "District",
SUM(CASE WHEN bo.state IN ('won') THEN 1 ELSE 0 END) AS "Won",
SUM(CASE WHEN bo.state IN ('lost') THEN 1 ELSE 0 END) AS "Lost",
Count(bo.state) AS "Total",
Round(100 * SUM(CASE WHEN bo.state IN ('won') THEN 1 ELSE 0 END) / Count(bo.state)) AS "% Won"
FROM bks b
INNER JOIN bks_opps bo ON bo.id = b.opportunity_id
INNER JOIN pckgs p ON p.id = b.package_id
INNER JOIN bts bt ON bt.id = p.boat_id
INNER JOIN addresses a ON a.addressable_type = 'Boat' AND a.addressable_id = bt.id
INNER JOIN districts d ON d.id = a.district_id
WHERE bo.trip_start BETWEEN '2016-05-12' AND '2016-06-12'
GROUP BY d.name;
This returns incorrect data (The values are way higher than expected). However, when I get rid of all the joins and stop grouping by district - the numbers are correct (Counting the toal # of opportunities). Anybody that can spot what I am doing wrong? The most related question on here is this one.
Example data:
District | won | lost | total
----+---------+---------+------
1 | 42 | 212 | 254
Expected data:
District | won | lost | total |
----+---------+---------+--
1 | 22 | 155 | 177
Formatted comment here:
I would venture a guess that one of your join conditions is at fault here, but with the provided structure it is impossible to say.
For instance, you have this join INNER JOIN pckgs p ON p.id = b.package_id, but package_id is not listed as a column in bks.
And these joins look especially suspect:
INNER JOIN pckgs p ON p.id = b.package_id
INNER JOIN bts bt ON bt.id = p.boat_id
If a boat can exist in multiple packages, it will be an issue.
To troubleshoot, start with the simplest query you can:
SELECT b.opportunity_id
FROM bks b
Then leave the select alone, and proceed to add in each join:
SELECT b.opportunity_id
FROM bks b
INNER JOIN pckgs p ON p.id = b.package_id
At some point you'll likely see a jump in the number of rows returned. Whichever JOIN you added last is your issue.
I have a query that I can get right. So here is my scenario:
I have 1 parent table called 'Couriers', then 1 courier may have 1 or many 'Messengers' then Couriers has a 2nd table called 'Control' where I control how many messengers can a courier have.
The structures goes like this:
'Courier'
idCourier(pk)
181
162
101
'Messenger'
idMessenger (pk), idCourier (fk)
1 101
2 181
3 101
4 101
5 162
'Control'
idCourier(pk, fk), maxNumberOfMessengers, idSupervisor
181 20 146
181 20 149
162 10 129
162 10 130
162 10 138
162 10 139
101 0 83
101 0 86
So with the next query:
SELECT COUNT(G.idCourier) AS NUM_COURIER, G.idMessenger, SUM(T.maxNumberOfMessengers) AS TOTAL
FROM Courier M
LEFT JOIN Messenger G ON M.idCourier = G.idCourier
LEFT JOIN Control T ON T.idCourier = G.idCourier AND T.idCourier = M.idCourier
GROUP BY G.idMessenger
I get:
NUM_COURIER G.idMessenger TOTAL
2 181 40
4 162 40
6 101 0
And I was expecting:
NUM_COURIER G.idMessenger TOTAL
1 181 40
3 162 40
1 101 0
What am I missing or doing wrong in my query???
Thanks in advance!!:)
How many messengers do we have per courier?
SELECT idCourier, COUNT(*) CourierCount FROM Messenger GROUP BY idCourier
Now join this and compare to control:
SELECT CO.idcourier,
CO.maxnumberofmessengers,
CC.couriercount
FROM control CO
INNER JOIN (SELECT idcourier,
Count(*) CourierCount
FROM messenger
GROUP BY idcourier) CC
ON CC.idcourier = CO.idcourier
I am not familiar with Oracle so I hope this is helpful as this is how you would do this with MS Sql.
SELECT COUNT(G.idCourier) AS NUM_COURIER,
m.idcourier,
(
SELECT sum(maxnumberofmessengers)
FROM CONTROL con
WHERE con.idcourier = m.idcourier
GROUP BY con.idcourier
) AS TOTAL
FROM Courier M
JOIN Messenger G ON M.idCourier = G.idCourier
GROUP BY m.idcourier
My previous query incorrectly assumed that we needed to count the number of courier entries in the Control table, while also summing the number of messengers.
SELECT COUNT(T.idCourier) AS NUM_COURIER, T.idCourier, SUM(T.maxNumberOfMessengers) AS TOTAL
FROM Control T
GROUP BY T.idCourier
I see now that we need to get the number of Messengers. So a sub query is required:
SELECT Couriers.CourierCount as NUM_COURIER, Couriers.idCourier, MaxMessengers.TOTAL
FROM
(SELECT M.idCourier, COUNT(*) CourierCount FROM Messenger M GROUP BY M.idCourier) Couriers
JOIN(SELECT C.idCourier, SUM(C.maxNumberOfMessengers) AS TOTAL From Control C GROUP BY C.idCourier) MaxMessengers
ON MaxMessengers.idCourier = Couriers.idCourier
courier table and control table is connected by idcourier and courier table and messenger table is also connected by idcourier but messenger table and control table are not connected at all. Another thing is idcourier alone can not be pk in control table as per its data. it has duplicate data.
select t1.idcourier,cnt,sm
from (
SELECT COURIER.IDCOURIER,
COUNT(MESSENGER.IDMESSENGER) as cnt
FROM COURIER
left JOIN MESSENGER
ON COURIER.IDCOURIER = MESSENGER.IDCOURIER
GROUP BY COURIER.IDCOURIER ) t1
inner join (
SELECT COURIER.IDCOURIER,
SUM(CONTRAL.MAXNUMBEROFMESSENGERS) as sm
FROM COURIER
left JOIN CONTRAL
ON COURIER.IDCOURIER = CONTRAL.IDCOURIER
GROUP BY COURIER.IDCOURIER )t2 on t1.idcourier = t2.idcourier;
with one as
(Select sno = ROW_NUMBER()OVER (order by complaint_id), Complaint_Id, Complaint.ComplaintType_id, Complaint.complaintProfileId, Complaint.Description,
Complaint.Email, Complaint.PriorityLevel_id, Complaint.Date_Complained, Complaint.Status, Complaint.AdminComments, Complaint.Phone, Complaint.Evidence
from Complaints Complaint )
The result of this query is (not the entire result)
sno complaintProfileId
1 14
2 15
3 15
4 14
5 14
6 13
The second subquery:
two as
(SELECT Complaint.complaintProfileId,
CASE
WHEN MMB_Name IS NOT NULL THEN MMB_Name
WHEN UPPMembership.profile_id IS NOT NULL THEN 'UPP'
ELSE 'Not found'
END as Name
FROM Complaints Complaint
LEFT JOIN MMBMembership
ON MMBMembership.profile_id = Complaint.complaintProfileId
left JOIN MMB_BusinessProfiles mmbProfiles
ON mmbProfiles.MMB_id = MMBMembership.MMB_id
LEFT JOIN UPPMembership
ON UPPMembership.profile_id = Complaint.complaintProfileId)
complaintProfileId Name
14 UPP
15 Marlon
15 Marlon
14 UPP
14 UPP
13 Rodolfo
So this is where I am having trouble with
select one.*, two.Name
from one join two
on one.complaintProfileId = two.complaintProfileId
This query returns 36 records. id 14 is being returned 9times and 15-6times and so on..
I am doing a inner join but still not sure
Thanks
Sun
You need to join on a unique key. Each '14' on the left side is being joined to each of the three '14's on the right side. (3x3=9)