MySQL one to many data relationship with added complications - mysql

I have a database in which there are multiple posts. Each post can be associated with one or more location. Each location is then associated with one country.
This is handled through four tables:
post (with the id and post_title)
postlocation (with the fields post_id and location_id - to allow a one to many relationship)
location (with the fields id, location_title and country_id)
country (with the fields, id and country_title)
I want to perform a simple, effective select to retrieve a list of posts and each one's associated locations and each of those locations' country.
I'm at a loss as to how to best achieve this, and any help would be most welcome. Thank you.

Use LEFT JOIN:
SELECT post.*, location.*, country.*
FROM post
LEFT JOIN postlocation ON post.id = postlocation.post_id
LEFT JOIN location ON postlocation.location_id = location.id
LEFT JOIN country ON location.country_id = country.id
Here's an explanation of how LEFT JOIN works: http://www.mysqltutorial.org/mysql-left-join.aspx
The MySQL LEFT JOIN clause works like this: when a row from the left
table matches a row from the right table based on join_condition, the
row’s content are selected as an output row. When row in the left
table has no match it is still selected for output, but combined with
a “fake” row from the right table that contains NULL in all columns.
In short, the MySQL LEFT JOIN clause allows you to select all rows
from the left table even there is no match for them in the right
table.
When you have multiple LEFT JOINs, then in each case it uses the cumulative results so far as the "left" table and the table your are joining on as the "right" table.
So the query above will return one row for every post/location/country. Note that this means there will be potentially several rows with the same post.* data (one for each postlocation associated with taht post).
And if a post has no postlocations associated with it, that post will still show up in the results (but with null rows for location.* and country.*). Similarly, if a location has no country associated it with it, the post/location rows will still show up in the output (but with null rows for country.*). This is the advantage of LEFT JOIN -- you always get all the rows from the table on the "left".

Related

include null and zero in count() from related table

I would like to list in table (staging) the number of related records from table (studies).
So far this statement works well but returns only the rows where there are >0 related records:
SELECT staging.*,
COUNT(studies.PMID) AS refcount
FROM studies
LEFT JOIN staging
ON studies.rs_number = staging.rs
GROUP BY staging.idstaging;
How can I adjust this statement to list ALL rows in table (staging) including where there are zero or null related records from table (studies)?
Thank you
You have the tables in the wrong order in the LEFT JOIN:
SELECT staging.*, COUNT(studies.PMID) AS refcount
FROM staging LEFT JOIN
studies
ON studies.rs_number = staging.rs
GROUP BY staging.idstaging;
LEFT JOIN keeps everything in the first ("left") table and all matching rows in the second. If you want to keep everything in the staging table, then put it first.
And, in case anyone wants to complain about the use of staging.* with GROUP BY. This particular usage is (presumably) ANSI compliant because staging.idstaging is (presumably) a unique id in that table.

MySQL SELECT from two tables with COUNT

i have two tables as below:
Table 1 "customer" with fields "Cust_id", "first_name", "last_name" (10 customers)
Table 2 "cust_order" with fields "order_id", "cust_id", (26 orders)
I need to display "Cust_id" "first_name" "last_name" "order_id"
to where i need count of order_id group by cust_id like list total number of orders placed by each customer.
I am running below query, however, it is counting all the 26 orders and applying that 26 orders to each of the customer.
SELECT COUNT(order_id), cus.cust_id, cus.first_name, cus.last_name
FROM cust_order, customer cus
GROUP BY cust_id;
Could you please suggest/advice what is wrong in the query?
You issue here is that you have told the database how these two tables are 'connected', or what they should be connected by:
Have a look at this image:
~IMAGE SOURCE
This effectively allows you to 'join' two tables together, and use a query between them.
so you might want to use something like:
SELECT COUNT(B.order_id), A.cust_id, A.first_name, A.last_name
FROM customer A
LEFT JOIN cust_order B //this is using a left join, but an inner may be appropriate also
ON (A.cust_id= B.Cust_id) //what links them together
GROUP BY A.cust_id; // the group by clause
As per your comment requesting some further info:
Left Join (right joins are almost identical, only the other way around):
The SQL LEFT JOIN returns all rows from the left table, even if there are no matches in the right table. This means that if the ON clause matches 0 (zero) records in right table, the join will still return a row in the result, but with NULL in each column from right table. ~Tutorials Point.
This means that a left join returns all the values from the left table, plus matched values from the right table or NULL in case of no matching join predicate.
LEFT joins will be used in the cases where you wish to retrieve all the data from the table in the left hand side, and only data from the right that match.
Execution Time
While the accepted answer in this case may work well in small datasets, it may however become 'heavy' in larger databases. This is because it was not actually designed for this type of operation.
This was the purpose of Joins to be introduced.
Much work in database-systems has aimed at efficient implementation of joins, because relational systems commonly call for joins, yet face difficulties in optimising their efficient execution. The problem arises because inner joins operate both commutatively and associatively. ~Wikipedia
In practice, this means that the user merely supplies the list of tables for joining and the join conditions to use, and the database system has the task of determining the most efficient way to perform the operation. A query optimizer determines how to execute a query containing joins. So, by allowing the dbms to choose the way your data is queried, you can save a lot of time.
Other Joins/Summary
AN INNER JOIN will return data from both tables where the keys in each table match
A LEFT JOIN or RIGHT JOIN will return all the rows from one table and matching data from the other table.
Use a join when you want to query multiple tables.
Joins are much faster than other ways of querying >=2 tables (speed can be seen much better on larger datasets).
You could try this one:
SELECT COUNT(cus_order.order_id), cus.cust_id, cus.first_name, cus.last_name
FROM cust_order cus_order, customer cus
WHERE cus_order.cust_id = cus.cust_id
GROUP BY cust_id;
Maybe an left join will help you
SELECT COUNT(order_id), cus.cust_id, cus.first_name, cus.last_name ]
FROM customer cus
LEFT JOIN cust_order co
ON (co.cust_id= cus.Cust_id )
GROUP BY cus.cust_id;

Specific selection of data from two SQL tables using Mysql database

I have a mysql database and i want to make a specific selection. Here is the scenario:
First table
Road list data about cargo vehicles.
roadListNumber(primary_key), vehicle, driver, startWorkTime, endWorkTime and so on.
Second table
Cargo zones mapped with the primary key of the first table.
roadListNumber(foreign_key), zoneId, timeInside, spentMoney and so on.
The problem is that not every vehicle goes to the cargo zones so some of the road lists are not mapped with cargo zones (the second table ) and here comes my problem and the question:
How can i select all the roadlist from first table and join the result with the second table ( cargo zones ) without skipping the roadlist which are not mapped with cargo zones?
You can use LEFT JOIN to get data... also use GROUP BY to avoid repeated data..
SELECT rl.roadListNumber,rl.vehicle,cz.zoneId,cz.spentMoney
FROM road_list rl
LEFT JOIN cargo_zone cz on (rl.roadListNumber=cz.roadListNumber)
GROUP BY rl.roadListNumber
You were already using the correct word (JOIN). You can use a LEFT OUTER JOIN in order to fetch all the records in the first (or left) table, and relate them to their corresponding records from the second (or right) table according to the ON clause.
Notice the usage of the left and right table terms here and how it relates to LEFTOUTER JOIN.
If there's no matching record on the second table, you will get NULL on the second table's columns in the result set.
SELECT * FROM roadlist rl
LEFT OUTER JOIN cargozones cz ON rl.roadlistnumber = cz.roadlistnumber
There are many kinds of JOIN. If you were using an INNER JOIN, for instance, you would only get the records that have a match on the second table.
See this blog post for a good visual explanation on how do SQL joins work: Coding Horror: A Visual Explanation of SQL Joins.

How to join two tables and get specific records only

How to join two tables and get specific records only?
I have two tables
Supplier -- Columns (supp_id,supp_code,supp_name,address)
SelectedSuppliers -- columns (supplier_id,is_selected, date_a)
I load the all the suppliers to grid view and select specific suppliers by check box
For specific date from supplier table then it goes to SelectedSupplier table .
When I load saved suppliers from SelectedSupplier table I need to view all the suppliers from two tables. Which means if I added a new supplier it should be display when I'm loading second time .
This is my query
SELECT
`supplier`.`supp_id`,
`supplier`.`supp_name`,
`supplier`.`address`,
`supplier`.`supp_code`,
`SelectedSuppliers `.`is_selected`
FROM
`SelectedSuppliers `
LEFT JOIN
`supplier` ON (`shop_list`.`supplier_id` = `supplier`.`supp_id`)
WHERE
SelectedSuppliers.date_a = '2013-1-5'
It works but load SelectedSupplier records only not all records
Thanks.
SELECT
`supplier`.`supp_id`,
`supplier`.`supp_name`,
`supplier`.`address`,
`supplier`.`supp_code`,
`SelectedSuppliers `.`is_selected`
FROM 'supplier',`SelectedSuppliers`
LEFT JOIN `supplier`
ON (`shop_list`.`supplier_id` = `supplier`.`supp_id`)
where SelectedSuppliers.date_a = '2013-1-5'
Please have a look at the image
Just reverse the join order and move the condition into the ON clause to allow the left join to still work:
SELECT
`supplier`.`supp_id`,
`supplier`.`supp_name`,
`supplier`.`address`,
`supplier`.`supp_code`,
`SelectedSuppliers `.`is_selected`
FROM `supplier`
LEFT JOIN `SelectedSuppliers `
ON `shop_list`.`supplier_id` = `supplier`.`supp_id`
AND SelectedSuppliers.date_a = '2013-1-5'
By selecting from suppliers first, then left joining you'll get every supplier row.
Note: It is commonly (and incorrectly) believed that the ON clause may only have "key related" conditions, but in fact it may contain any condition (even one not related to the tables being joined!)
It's not at all clear why you have a reference to shop_list, when that table or alias doesn't appear in your query, or why one of your table names includes a trailing space,
From your description, I think you want supplier to be on the left side of the LEFT JOIN (to return all rows from the supplier table.
(I replaced the reference to shop_list with a reference to the SelectedSuppliers. I left the trailing space on the table name, as in your example query.)
SELECT s.supp_id
, s.supp_name
, s.address
, s.supp_code
, e.is_selected
FROM `supplier` s
LEFT
JOIN `SelectedSuppliers ` e
ON e.supplier_id = s.supp_id
AND e.date_a = '2013-1-5'
All rows will be returned from the table on the left side (in this query, that's supplier), along with any matching rows from the table on the right side.
The value for is_selected in will be NULL when there is no matching row in the SelectedSuppliers table. This can easily be replaced with a 0, if that's desired, by wrapping that in an IFNULL function.
If your intent is to EXCLUDE suppliers that are already selected, we can add a simple predicate to the query to eliminate the matching rows:
WHERE e.supplier_id IS NULL
That will return rows from supplier where there is no matching row in the SelectedSuppliers table,
Use this form
SELECT A1,A2,...
FROM TABLE1,TABLE2,TABLE3,....
WHERE ......
Note: From table names creates a cartesian product of all the values out of which you choose by specifying the where clause.
whatever information you are putting into is_selected column to know whether that information has been supplied or not use that in your where condition. Suppose by default it is 0 (if that is not selected) and you want those records to be loaded then simply put where SelectedSuppliers.is_selected = 0

Learning LEFT JOIN in MySQL

dear all.i newbie at web programming and until now i still have learn about MySQL syntax.
for now i start to use LEFT JOIN method. i know that this method use for make normalization between two or many tables. I have posted a question in SO, then I receive an Answer which make me confuse. I have modified that answer,but i still confuse because it use LEFT JOIN just for one table. whether the LEFT JOIN can be used in one table?
You can LEFT JOIN a table with itself, just like you can JOIN a table with itself. Your purpose will usually be different, because the specific characteristic of a LEFT JOIN is ensuring a row in the output when no corresponding row exists on the right, of course; you can select those rows which have specifically been selected that way by checking for NULL for the "other part" of the row, the part that would normally come from the right-side table.
Consider for example a table Product with columns ID, primary key, Name, Category, and Cost; you want info about products that are cheapest in their category. Then...:
SELECT P1.Name, P1.Category, P1.Cost
FROM Product AS P1
LEFT JOIN Product AS P2
ON (P1.Category = P2.Category and P1.Cost > P2.Cost)
WHERE P2.ID IS NULL
is an example of a "left join of a table to itself" which will answer the "you want" spec (if more than one item has the equal-lowest cost in a category you'll get them all -- the query actually gives you the items such that no item in their category is cheaper and has no checks for items of equal cost;-).