This query
SELECT station_id, station_name,
COUNT(event_station) as `total_visit_count`
FROM taps AS t
JOIN event_stations AS s
ON t.event_station = s.station_id
WHERE s.event_id=6
GROUP BY s.station_id
ORDER BY s.station_id;
returns
+------------+--------------+-------------------+
| station_id | station_name | total_visit_count |
+------------+--------------+-------------------+
| 5 | Station one | 24 |
| 6 | Station two | 35 |
| 7 | St. Pancras | 34 |
+------------+--------------+-------------------+
which is just fine.
However, there are some stations in taps which have not been visited and I would like them to be shown with a total_visit_count of zer0.
+------------+--------------+-------------------+
| station_id | station_name | total_visit_count |
+------------+--------------+-------------------+
| 5 | Station one | 24 |
| 6 | Station two | 35 |
| 7 | St. Pancras | 34 |
| 8 | Station four | 0 |
+------------+--------------+-------------------+
How do I rewrite my query to to that? I imagine some kind of JOIN is required, but I can't quite see it :-(
[Update]
describe event_Stations;
+--------------+------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+------------+------+-----+---------+----------------+
| station_id | int(11) | NO | PRI | NULL | auto_increment |
| event_id | int(11) | NO | | NULL | |
| station_name | text | NO | | NULL | |
| allocated | tinyint(1) | NO | | 0 | |
+--------------+------------+------+-----+---------+----------------+
4 rows in set (0.20 sec)
describe taps;
+---------------+-----------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-----------+------+-----+-------------------+-------+
| tag_id | int(11) | NO | | NULL | |
| time_stamp | timestamp | NO | | CURRENT_TIMESTAMP | |
| event_station | int(11) | NO | | NULL | |
| device_id | text | YES | | NULL | |
| device_type | text | YES | | NULL | |
| event_id | int(11) | NO | | NULL | |
+---------------+-----------+------+-----+-------------------+-------+
6 rows in set (0.00 sec)
select * from event_stations where event_id=6;
+------------+----------+-----------------+-----------+
| station_id | event_id | station_name | allocated |
+------------+----------+-----------------+-----------+
| 5 | 6 | Station one | 0 |
| 6 | 6 | Station two | 0 |
| 7 | 6 | St. Pancras | 0 |
| 8 | 6 | Station three | 0 |
| 9 | 6 | Station four | 0 |
| 10 | 6 | Station five | 0 |
| 11 | 6 | Station six | 0 |
| 12 | 6 | Station seven | 0 |
| 13 | 6 | Station eight | 0 |
| 14 | 6 | Station nine | 0 |
| 15 | 6 | Station ten | 0 |
| 16 | 6 | Station eleven | 0 |
+------------+----------+-----------------+-----------+
12 rows in set (0.00 sec)
First, swap the order of your join, so the primary table is sorted first (this is for organizational purposes only).
Then, use a LEFT JOIN to accomplish what you're looking for. This will ensure you pull all event_stations records (the left portion of the join), even if there is no corresponding record in the taps table (the right portion of the join). In place of the missing taps, you'll get NULL values.
COUNT will ignore nulls in aggregate, so will only return the count of non-null records. Thus, it will return 0 for your missing event_stations records.
SELECT
station_id,
station_name,
COUNT(event_station) as `total_visit_count`
FROM event_stations AS s
LEFT JOIN taps AS t
ON t.event_station = s.station_id
WHERE s.event_id = 6
GROUP BY s.station_id
ORDER BY s.station_id;
Alternatively, you could just use a RIGHT JOIN with your original join order. I personally don't like doing that, though, because I'm a LTR reader (first in order is more important).
Related
I have a listing_categories table that has many listing_plans and listings, and many subcategories. I am trying to write a view to show the listing categories with listing_plan count, listings count and subcategory count.
Here is my listing_categories table:
MariaDB [railsapp_development]> describe listing_categories;
+---------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| website_id | int(11) | YES | MUL | NULL | |
| listing_category_id | int(11) | YES | | NULL | |
| name | varchar(255) | YES | | NULL | |
| slug | varchar(255) | YES | | NULL | |
| description | text | YES | | NULL | |
| category_card | text | YES | | NULL | |
| listing_card | text | YES | | NULL | |
| layout | varchar(255) | YES | | NULL | |
| status | int(11) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
| keywords | varchar(255) | YES | | NULL | |
+---------------------+--------------+------+-----+---------+----------------+
And the view I am trying to write:
create or replace view `listing_category_details` AS
select
cats1.*,
count(l.id) as listing_count,
count(cats2.id) as subcategory_count,
count(lp.id) as plan_count
from
listing_categories as cats1
left join
listings as l on cats1.id = l.listing_category_id
left join
listing_plans as lp on cats1.id = lp.listing_category_id
inner join
listing_categories as cats2 on cats1.listing_category_id = cats2.id
group by
cats1.id
order by
cats1.name asc;
The output is incorrect, it is not showing the right count, as follows:
MariaDB [railsapp_development]> select id, slug, name, listing_count, subcategory_count, plan_count from listing_category_details limit 10;
+----+-------------------+-------------------+---------------+-------------------+------------+
| id | slug | name | listing_count | subcategory_count | plan_count |
+----+-------------------+-------------------+---------------+-------------------+------------+
| 17 | ares | Ares | 22 | 22 | 22 |
| 30 | automotive | Automotive | 16 | 16 | 16 |
| 19 | crist-osinski-inc | Crist-Osinski Inc | 12 | 12 | 12 |
| 29 | esl-cologne | ESL Cologne | 20 | 20 | 20 |
| 18 | executive-office | Executive Office | 22 | 22 | 22 |
| 27 | gfinity-london | GFinity London | 24 | 24 | 24 |
| 25 | hephaestus | Hephaestus | 28 | 28 | 28 |
| 24 | iem-championship | IEM Championship | 14 | 14 | 14 |
| 26 | league-all-stars | League All Stars | 30 | 30 | 30 |
| 21 | machinery | Machinery | 14 | 14 | 14 |
+----+-------------------+-------------------+---------------+-------------------+------------+
In the above example none of the figures are corect, for instance each listing_category has exactly 2 plans.
What am I doing wrong?
Use COUNT(DISTINCT):
select cats1.*,
count(distinct l.id) as listing_count,
count(distinct cats2.id) as subcategory_count,
count(distinct lp.id) as plan_count
from listing_categories cats1 left join
listings l
on cats1.id = l.listing_category_id left join
listing_plans lp
on cats1.id = lp.listing_category_id inner join
listing_categories cats2
on cats1.listing_category_id = cats2.id
group by cats1.id
order by cats1.name asc;
COUNT() just counts the number of non-NULL values. You are joining along a hierarchy, so the rows get multiplied as you descend the hierarchy.
I need to use a data visualization tool that can only query a single source for a given chart. I have three tables with the data I need to visualize. So, I need to combine them into a single view or output table. Here are the table schemas:
MySQL [bdCaloriesNeeded]> desc activity;
+---------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+----------+------+-----+---------+-------+
| id | int(11) | YES | | NULL | |
| name | text | YES | | NULL | |
| Gender | text | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| length | text | YES | | NULL | |
| weight | int(11) | YES | | NULL | |
| exercise | int(11) | YES | | NULL | |
| food_consumed | int(11) | YES | | NULL | |
| date | datetime | YES | | NULL | |
+---------------+----------+------+-----+---------+-------+
MySQL [bdCaloriesNeeded]> desc exercise;
+---------------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------+------+-----+---------+-------+
| Gender | text | YES | | NULL | |
| Min_Age | int(11) | YES | | NULL | |
| Max_Age | int(11) | YES | | NULL | |
| min_exercise_hours | int(11) | YES | | NULL | |
| med_exercise_hours | int(11) | YES | | NULL | |
| high_exercise_hours | int(11) | YES | | NULL | |
+---------------------+---------+------+-----+---------+-------+
MySQL [bdCaloriesNeeded]> desc food;
+---------------------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------+------+-----+---------+-------+
| size | text | YES | | NULL | |
| min_pounds | int(11) | YES | | NULL | |
| max_pounds | int(11) | YES | | NULL | |
| min_food_oz_per_day | int(11) | YES | | NULL | |
| max_food_oz_per_day | int(11) | YES | | NULL | |
+---------------------+---------+------+-----+---------+-------+
Here's the actual source data in the above tables:
MySQL [bdCaloriesNeeded]> select * from activity;
+------+----------+--------+------+--------+--------+----------+---------------+---------------------+
| id | name | Gender | age | length | weight | exercise | food_consumed | date |
+------+----------+--------+------+--------+--------+----------+---------------+---------------------+
| 14 | spot | M | 2 | 2'7" | 13 | 5 | 13 | 2017-10-08 00:00:00 |
| 67 | princess | F | 6 | 3'3" | 75 | 3 | 15 | 2017-09-05 00:00:00 |
+------+----------+--------+------+--------+--------+----------+---------------+---------------------+
MySQL [bdCaloriesNeeded]> select * from exercise
+--------+---------+---------+--------------------+--------------------+---------------------+
| Gender | Min_Age | Max_Age | min_exercise_hours | med_exercise_hours | high_exercise_hours |
+--------+---------+---------+--------------------+--------------------+---------------------+
| M | 1 | 2 | 1 | 4 | 6 |
| M | 3 | 7 | 1 | 3 | 4 |
| M | 8 | 15 | 1 | 2 | 2 |
| F | 1 | 2 | 1 | 4 | 6 |
| F | 3 | 7 | 1 | 3 | 5 |
| F | 8 | 15 | 1 | 2 | 2 |
+--------+---------+---------+--------------------+--------------------+---------------------+
MySQL [bdCaloriesNeeded]> select * from food;
+--------+------------+------------+---------------------+---------------------+
| size | min_pounds | max_pounds | min_food_oz_per_day | max_food_oz_per_day |
+--------+------------+------------+---------------------+---------------------+
| small | 1 | 10 | 12 | 18 |
| medium | 11 | 30 | 15 | 30 |
| large | 31 | 100 | 25 | 50 |
+--------+------------+------------+---------------------+---------------------+
Here's the SQL I'm executing:
SELECT activity.id, activity.name, activity.Gender, activity.age, activity.weight, activity.exercise, activity.date, exercise.min_exercise_hours, exercise.high_exercise_hours, food.size, food.min_food_oz_per_day, food.max_food_oz_per_day
from activity, exercise, food
where (
activity.exercise between exercise.min_exercise_hours and exercise.high_exercise_hours
)
and
(
activity.weight between food.min_pounds and food.max_pounds
)
and
(
activity.Gender = exercise.Gender
)
Here's the undesired result I'm getting:
+------+----------+--------+------+--------+----------+---------------------+--------------------+---------------------+--------+---------------------+---------------------+
| id | name | Gender | age | weight | exercise | date | min_exercise_hours | high_exercise_hours | size | min_food_oz_per_day | max_food_oz_per_day |
+------+----------+--------+------+--------+----------+---------------------+--------------------+---------------------+--------+---------------------+---------------------+
| 14 | spot | M | 2 | 13 | 5 | 2017-10-08 00:00:00 | 1 | 6 | medium | 15 | 30 |
| 67 | princess | F | 6 | 75 | 3 | 2017-09-05 00:00:00 | 1 | 6 | large | 25 | 50 |
| 67 | princess | F | 6 | 75 | 3 | 2017-09-05 00:00:00 | 1 | 5 | large | 25 | 50 |
+------+----------+--------+------+--------+----------+---------------------+--------------------+---------------------+--------+---------------------+---------------------+
I'm getting two rows for Princess. I need one row for each dog. The desired result should use Princess's's weight to look up the correct range of food per day, and use her gender and age to look up the correct range of exercise.
I've been banging on this for hours, can't see what doing wrong here.
So interestingly your question says that the tables are Unrelated but they are actually related and this is the whole point of a relational database, to join data based on those relationships.
The issue is that your exercise table is only being joined on exercise hours using the between so princess matches rows 4 and 5 in the exercise table. (the first where clause matches rows 1 and 2 also but the later where clause limits the Gender)
It looks to me like you should also limit the match on the exercise table to age as well as exercise and gender
so add
and (activity.age between exercise.min_age and exercise.max_age)
Also personally i like to use JOIN clauses rather than WHERE - it keeps all the stuff together.
SELECT activity.id,
activity.name,
activity.Gender,
activity.age,
activity.weight,
activity.exercise,
activity.date,
exercise.min_exercise_hours,
exercise.high_exercise_hours,
food.size,
food.min_food_oz_per_day,
food.max_food_oz_per_day
FROM activity
JOIN exercise
ON activity.exercise BETWEEN exercise.min_exercise_hours AND exercise.high_exercise_hours
AND activity.Gender = exercise.Gender
AND activity.age BETWEEN exercise.min_age AND exercise.max_age
JOIN food
ON activity.weight BETWEEN food.min_pounds AND food.max_pounds
Since you are looking for things that may be OUTSIDE of the ranges suggested you may want to consider LEFT JOIN on the exercise and food tables, so that the dogs on the activity table that fall outside of any range will still show up (with NULL values for the missing data for the other table.)
just change the join lines to LEFT JOIN like so:
LEFT JOIN exercise
LEFT JOIN food
See also: What is the difference between "INNER JOIN" and "OUTER JOIN"?
I have a mysql table that holds data for team games.
Objective:
Count the number of times other SquadID's have have shared the same Team value as SquadID=21
// Selections table
+--------+---------+------+
| GameID | SquadID | Team |
+--------+---------+------+
| 1 | 5 | A |
| 1 | 7 | B |
| 1 | 11 | A |
| 1 | 21 | A |
| 2 | 5 | A |
| 2 | 7 | B |
| 2 | 11 | A |
| 2 | 21 | A |
| 3 | 5 | A |
| 3 | 7 | B |
| 3 | 11 | A |
| 3 | 21 | A |
| 4 | 5 | A |
| 4 | 11 | B |
| 4 | 21 | A |
| 5 | 5 | A |
| 5 | 11 | B |
| 5 | 21 | A |
| 6 | 5 | A |
| 6 | 11 | B |
| 6 | 21 | A |
+--------+---------+------+
// Desired Result
+---------+----------+
| SquadID | TeamMate |
+---------+----------+
| 5 | 6 |
| 7 | 0 |
| 11 | 3 |
| 21 | 6 |
+----------+---------+
I've attempted to use a subquery specifying the specific player I wish to compare with and because this subquery has multiple rows, I've used in instead of =.
// Current Query
SELECT
SquadID,
COUNT(Team IN (SELECT Team FROM selections WHERE SquadID=21) AND GameID IN (SELECT GameID FROM selections WHERE SquadID=21)) AS TeamMate
FROM
selections
GROUP BY
SquadID;
The result I'm getting is the number of Games a user has played rather than the number of games a user has been on the same team as SquadID=21
// Current Result
+---------+----------+
| SquadID | TeamMate |
+---------+----------+
| 5 | 6 |
| 7 | 3 |
| 11 | 6 |
| 21 | 6 |
+---------+----------+
What am I missing?
// DESCRIBE selections;
+---------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| GameID | int(11) | NO | PRI | 0 | |
| SquadID | int(4) | NO | PRI | NULL | |
| Team | char(1) | NO | | NULL | |
| TeamID | int(11) | NO | | 1 | |
+---------+---------+------+-----+---------+-------+
General rule is to avoid nested selects and look for a better way of logically arranging joins. Lets look at a cross join:
From selections s1
inner join selects s2 on s1.gameid = s2.gameid and s1.team = s2.team
This will produce a cross joined list of each squadID that participated with another squadID (IE: they were in the same game and on same team). We are only interested in the times where the squad participated with squad 21, so add a where clause:
where s2.squadid = 21
Then it's simply choosing the field/count you want:
select s1.squad, count(1) as teammate
any aggregate needs a group by
group by s1.squad
Combine it together and give a go. Oddly, this will produce a list where squad 21 will be showing as playing on it's own team all 6 times. Adding a where clause can eliminate this
where s1.squadid <> s2.squadid
SELECT SquadID, count(t1.team) as TeamMate
FROM selections as t1 join
(select distinct team, gameid from selections where SquadID=21) as t2
on t1.Team=t2.Team and t1.Gameid=t2.Gameid
GROUP BY SquadID
I have a DB that has a bunch of businesses and the relationships between them. I am trying to find a way to get all Businesses that B2 sells to that B1 does not sell too. But Only on B2 where B1 and B2 sell to the same business.
V= Vendor, C = Client, Both are businesses but thinking in terms of Vendor/Client makes this easier to explain.
V1 -sells to-> C1 <- sells to- V2 -sells to-> C2
I am looking for all C2 that are not also in C1 for a specific V1 starting point.
My current tables:
mysql> DESCRIBE business;
+---------------+-------------------+------+-----+----------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------------+------+-----+----------+----------------+
| business_id | int(11) | NO | PRI | NULL | auto_increment |
| email | varchar(255) | YES | | | |
| name | varchar(255) | NO | | NULL | |
| city | varchar(255) | YES | | | |
| state | varchar(255) | YES | MUL | | |
| cCount | int(10) unsigned | YES | MUL | 0 | |
| scCount | int(10) unsigned | YES | MUL | 0 | |
| vCount | int(10) unsigned | YES | MUL | 0 | |
| svCount | int(10) unsigned | YES | MUL | 0 | |
+---------------+-------------------+------+-----+----------+----------------+
mysql> DESCRIBE relation_sells_to;
+---------+----------+------+-----+---------+--------+
| Field | Type | Null | Key | Default | Extra |
+---------+----------+------+-----+---------+--------+
| start | int(11) | NO | MUL | NULL | |
| end | int(11) | NO | MUL | NULL | |
+---------+----------+------+-----+---------+--------+
mysql> DESCRIBE vcvc;
+---------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------+------+-----+---------+-------+
| vendor | int(11) | NO | MUL | NULL | |
| client | int(11) | NO | | NULL | |
| vendor2 | int(11) | NO | | NULL | |
| client2 | int(11) | NO | | NULL | |
+---------+---------+------+-----+---------+-------+
I can use these two queries to get up to date results, But I have to drop the vcvc table every time I want to update it and it currently takes 15 min to build it. I also will not need access to all that info at any one time. I may need to generate theses lists for a few thousand at a time but not the full DB.
CREATE TABLE IF NOT EXISTS vcvc (INDEX vendor (vendor), INDEX client2 (client2))
SELECT r.start AS vendor, r.end AS client, r2.start AS vendor2, r3.end AS client2
FROM relation_sells_to AS r
JOIN relation_sells_to as r2 ON r.end = r2.end
JOIN relation_sells_to AS r3 ON r2.start = r3.start
WHERE r.start != r2.start
AND r.end != r3.end;
SELECT DISTINCT(client2), cCount, scCount, vCount, svCount
FROM vcvc
JOIN business AS b ON client2=b.business_id
WHERE vendor = ####
AND client2 NOT IN (SELECT client FROM vcvc WHERE vendor = ####)
ORDER BY cCount DESC;
Is there a way to do this in a single query so I dont have to build a whole new table every time I need to get this information? I currently have 500k relations and when I build this table I end up with over 100 million rows and most of those I don't need. Ideally I would be able to take an email(preferred) or business_id as the starting business/vendor, then just return a list of Business/clients with name, city, state, cCount, vCount and have them order in DESC order by vCount and probably LIMIT 20ish. Speed isn't a huge issue I really just want to be able to get current results without having to build a large table of which I need 20 of the 100+millions rows on it. I originally tried working with a temp table but because I cant "reopen" the temp table like my current query needs.
Thanks for the help.
Update with sample data and desired output.
Some of the cCount and vCounts might be off, I copied real data then modified it but I don't know if I updated all the numbers correctly as I added the required connections to show what I need.
mysql> SELECT * FROM business;
+-------------+----------------+----------------------+----------------+------------+--------+---------+--------+---------+
| business_id | email | name | city | state | cCount | scCount | vCount | svCount |
+-------------+----------------+----------------------+----------------+------------+--------+---------+--------+---------+
| 1 | bob#bob.com | Bobs Construction | Virginia Beach | Virginia | 62 | 3 | 0 | 0 |
| 2 | sue#bob.com | Upholstery by Sue | Austin | Texas | 20 | 3 | 4 | 4 |
| 3 | jim#bob.com | Jim & Associates | Crowley | Texas | 5 | 3 | 0 | 0 |
| 4 | jon#bob.com | Jon Jon architects | Costa Mesa | California | 67 | 3 | 0 | 0 |
| 5 | joe#bob.com | Joes Pizza | Hamden | Conecticut | 7 | 1 | 0 | 0 |
| 6 | tim#bob.com | Tims WIndows | Miami | Florida | 10 | 2 | 0 | 0 |
| 7 | ron#bob.com | Rons Hot Rods | Costa Mesa | California | 8 | 4 | 0 | 0 |
+-------------+----------------+----------------------+----------------+------------+--------+---------+--------+---------+
mysql> SELECT start, end FROM relation_sells_to;
+-------+--------+
| start | end |
+-------+--------+
| 3 | 1 |
| 3 | 2 |
| 2 | 4 |
| 2 | 5 |
| 4 | 2 |
| 1 | 5 |
| 4 | 5 |
| 4 | 6 |
| 4 | 7 |
+-------+--------+
-- Run code to build vcvc table. Code is above.
mysql> SELECT * FROM vcvc WHERE vendor = 3;
+--------+--------+---------+---------+
| vendor | client | vendor2 | client2 |
+--------+--------+---------+---------+
| 3 | 1 | 2 | 4 |
| 3 | 1 | 2 | 5 |
| 3 | 1 | 4 | 2 |
| 3 | 2 | 1 | 5 |
| 3 | 2 | 4 | 5 |
| 3 | 2 | 4 | 6 |
| 3 | 2 | 4 | 7 |
+--------+--------+---------+---------+
Desired Output:
Select client_id, name, city, state, cCount, vCount FROM MAGIC WHERE email = jim#bob.com
+-----------+---------------------+----------------+------------+--------+---------+
| client_id | name | city | state | cCount | vCount |
+-----------+---------------------+----------------+------------+--------+---------+
| 4 | Jon Jon architects | Costa Mesa | California | 67 | 0 |
| 6 | Tims WIndows | Miami | Florida | 10 | 0 |
| 7 | Rons Hot Rods | Costa Mesa | California | 8 | 0 |
| 5 | Joes Pizza | Hamden | Conecticut | 7 | 0 |
+-----------+---------------------+----------------+------------+--------+---------+
-- Ordered by cCount, business_id 2 is NOT in this list because 3 sells to 2 so I don't care that 4 sells to 2.
UPDATE 2:
http://sqlfiddle.com/#!9/fdcec/2
Here is a fiddle of it. The data in the fiddle is slightly different than the data above in that it has 2-3 more connections to properly show what I want.
Right outer join is similar to a Union of a venn diagram right?
I mean for A right outer Join B we should get all the rows of B and any matching rows in A.
For some reason I am confused with the following:
Assume table Orders:
mysql> select * from orders;
+------------+------------+---------+----------+---------+
| orderedon | name | partnum | quantity | remarks |
+------------+------------+---------+----------+---------+
| 1996-05-19 | TRUE-WHEEL | 76 | 3 | PAID |
| 1996-09-02 | TRUE-WHEEL | 10 | 1 | PAID |
| 1996-06-30 | TRUE-WHEEL | 42 | 8 | PAID |
| 1996-06-30 | BIKE SPEC | 54 | 10 | PAID |
| 1996-05-30 | BIKE SPEC | 23 | 8 | PAID |
| 1996-01-17 | BIKE SPEC | 76 | 11 | PAID |
| 1996-01-17 | LE SHOPPE | 76 | 5 | PAID |
| 1996-06-01 | LE SHOPPE | 10 | 3 | PAID |
| 1996-06-01 | AAA BIKE | 10 | 1 | PAID |
| 1996-07-01 | AAA BIKE | 76 | 4 | PAID |
| 1996-07-01 | AAA BIKE | 46 | 14 | PAID |
| 1996-07-11 | JACKS BIKE | 76 | 14 | PAID |
| 1996-05-15 | TRUE-WHEEL | 23 | 6 | PAID |
| 1996-05-30 | BIKE SPEC | 20 | 2 | PAID |
+------------+------------+---------+----------+---------+
14 rows in set (0.00 sec)
and table Part:
mysql> select * from part;
+---------+---------------+---------+
| partnum | description | price |
+---------+---------------+---------+
| 54 | PEDALS | 54.25 |
| 42 | SEATS | 24.50 |
| 46 | TIRES | 15.25 |
| 23 | MOUNTAIN BIKE | 350.45 |
| 76 | ROAD BIKE | 530.00 |
| 10 | TANDEM | 1200.00 |
+---------+---------------+---------+
6 rows in set (0.00 sec)
I was expecting that the following query:
select p.partnum p_partnum,p.description p_desc,p.price p_price,o.name o_name,o.partnum o_partnum from part p right outer join orders o on o.partnum=54;
Would give me all the rows of Orders and just the rows of part that have partnum=54.
But I get this:
mysql> select p.partnum p_partnum,p.description p_desc,p.price p_price,o.name o_name,o.partnum o_partnum from part p right outer join orders o on o.partnum=54;
+-----------+---------------+---------+------------+-----------+
| p_partnum | p_desc | p_price | o_name | o_partnum |
+-----------+---------------+---------+------------+-----------+
| NULL | NULL | NULL | TRUE-WHEEL | 76 |
| NULL | NULL | NULL | TRUE-WHEEL | 10 |
| NULL | NULL | NULL | TRUE-WHEEL | 42 |
| 54 | PEDALS | 54.25 | BIKE SPEC | 54 |
| 42 | SEATS | 24.50 | BIKE SPEC | 54 |
| 46 | TIRES | 15.25 | BIKE SPEC | 54 |
| 23 | MOUNTAIN BIKE | 350.45 | BIKE SPEC | 54 |
| 76 | ROAD BIKE | 530.00 | BIKE SPEC | 54 |
| 10 | TANDEM | 1200.00 | BIKE SPEC | 54 |
| NULL | NULL | NULL | BIKE SPEC | 23 |
| NULL | NULL | NULL | BIKE SPEC | 76 |
| NULL | NULL | NULL | LE SHOPPE | 76 |
| NULL | NULL | NULL | LE SHOPPE | 10 |
| NULL | NULL | NULL | AAA BIKE | 10 |
| NULL | NULL | NULL | AAA BIKE | 76 |
| NULL | NULL | NULL | AAA BIKE | 46 |
| NULL | NULL | NULL | JACKS BIKE | 76 |
| NULL | NULL | NULL | TRUE-WHEEL | 23 |
| NULL | NULL | NULL | BIKE SPEC | 20 |
+-----------+---------------+---------+------------+-----------+
19 rows in set (0.00 sec)
Why am I getting the extra rows? Why does it combine the row of Order with partnum=54 to all rows of `part?
Your query is
select p.partnum p_partnum,p.description p_desc,p.price p_price,o.name o_name,o.partnum o_partnum
from part p right outer join orders o on o.partnum=54;
You are going for right join so even if there is no match in the joining table on the right side it will display records and it is happening in this case of your query
same is for left join there all the records of the table on the left side will be displayed even if they dont match
Refer http://www.w3schools.com/sql/sql_join_right.asp
For detailed explanation
Hope this helps
FROM part p
RIGHT OUTER JOIN orders o
ON o.partnum=54
...only has a condition on order, what you need to add is a condition that the part also corresponds to the order, or the database will consider any part a match;
FROM part p
RIGHT OUTER JOIN orders o
ON o.partnum=54
AND o.partnum = p.partnum
Of course, if you only want to show the rows where partnum=54, you're better off moving the o.partnum=54 to a WHERE condition instead. JOIN conditions are usually for connecting tables, WHERE usually for filtering.
Because you have RIGHT JOIN to orders with join condition partnum=54 you will get all rows from orders joined with parts when partnum=54. You have one row with partnum=54 and that row joined with all rows (cross join) from parts.
You're using o.partnum = 54 on ON condition, that's why you're getting extra rows
in your result.
You need to put the condition o.partnum = 54 on where clause.
How about this
select p.partnum p_partnum,p.description p_desc,p.price p_price,o.name o_name,o.partnum o_partnum
from part p right outer join orders o
on o.partnum = p.partnum
where o.partnum=54;
Edit : You may refer to this beautiful article how the result set gets disturb when you
put condition on ON clause and Where.