Selecting/Inserting data between 3 tables - mysql

I think there are something wrong with my structure. I have 3 tables in the database. I want to show all the supply in a specific division. I did some trial and errors but I can't insert another supply in the same plan id. I wanted to add more supplies in one of specific division / specific plan id.Here's my query to select the supplies.
SELECT
division.acronym,
supply.`name`,
supply.unit,
supply.supply_id,
supply.price,
supply.estimated_budget,
supply.quantity
FROM
division
INNER JOIN plan ON plan.plan_id = division.division_id
INNER JOIN supply ON supply.supply_id = plan.plan_id
The table is only available at documentation. So, I insert my ERD diagram as an image.
ERD edited

I think you should put division_id and supply_id to plan table as FOREIGN KEYS to join all three tables.
Then your query should look like:
division
INNER JOIN plan ON plan.division_id=division.division_id
INNER JOIN supply ON supply.supply_id=plan.supply_id

Related

Dealing with polymorphic association: is there such a thing as "too many" LEFT JOIN?

I have ten tables (Product_A, Product_B, Product_C, etc.), each of them having a primary key pointing to a row in a the parent table Product.
Basically, I have applied the recommendations coming from the SQL antipattern book from Bill Karwin (this antipattern solution described here:
https://fr.slideshare.net/billkarwin/practical-object-oriented-models-in-sql/34-Polymorphic_Assocations_Exclusive_Arcs_Referential )
In order to load a child product, I use something like this:
SELECT * FROM Product
LEFT JOIN Product_A USING (product_id)
LEFT JOIN Product_B USING (product_id)
LEFT JOIN Product_C USING (product_id)
LEFT JOIN Product_D USING (product_id)
WHERE product_id = 1337
etc.
I fear that the more types of child table products I get, the more JOIN clause I will have to add, causing the query to end up incredibly slow.
Is using LEFT JOIN in order to prevent polymorphic associations antipattern still a solution if we work on tens of sub child tables?
Should I start thinking of up using a query on parent table Product in order to grab a "product_type" and then execute another query on the appropriate child table depending on the value stored in the "product_type" column in the parent table?
Update: first replies on this topic state that this is bad design and that I should create a single table combining the colums from the child tables. But each product type has its own attributes. To say it otherwise: "A TV might have a pixel count, but that wouldn't make much sense for a blender." #TomH
Thank you
MySQL has a hard limit on the number of joins. The limit is 61 joins, and it's not configurable (I looked at the source code and it's really just hard-coded). So if you have more than 62 product types, this is not going to work in a single query.
If the data were stored in the structure you describe, I would run a separate query per product type, so you don't make too many joins.
Or do a query against the Product table first, and then additional queries to the product-type specific tables if you need details.
For example, when would you need to gather the product-specific details all at once? On some kind of search page? Do you think you could design your code to show only the attributes from your primary Product table on the search page?
Then only if a user clicks on a specific product, you'd go to a different page to display detailed information. Or if not a different page, maybe it'd be a dynamic HTML thing where you expand a "+" button to fetch detailed info, and each time you do that, run an AJAX request for the details.
Yes, you can use the product_type (so called "discriminator") to help the DBMS produce a better query plan and avoid unnecessary joins. You can do something like this:
SELECT
*
FROM
Product
LEFT JOIN Product_A
ON product_type = 1 -- Or whatever is the actual value in your case.
AND Product.product_id = Product_A.product_id
LEFT JOIN Product_B
ON product_type = 2
AND Product.product_id = Product_B.product_id
LEFT JOIN Product_C
ON product_type = 3
AND Product.product_id = Product_C.product_id
LEFT JOIN Product_D
ON product_type = 4
AND Product.product_id = Product_D.product_id
WHERE
Product.product_id = 1337
The DBMS should be able to short-circuit all "branches" that don't have the right product_type and avoid the corresponding joins.1
Whether this is actually better than using a separate query to fetch product_type and then choosing the corresponding "special" query (and incurring another database round-trip) - that's something you should test. As always, test on the representative amounts of data!
1 At least Oracle or SQL Server would do that - please check for MySQL!
What kind of data is going into these tables? Is it simply metadata about the products? If that's the case you could create a tall table that describes each product.
For example, a Product_Details table that has three columns: product_id, product_data_key, value. Where product_data_key is what used to be the columns in Product_A, Product_B, Product_C...
You could even have a separate table that better describes product_data_key so it's just a foreign key in Product_Details.
Maybe change your design? One product can have many attributes (and many of the same attributes), and those attributes have values.
I suggest three tables:
Products ProductsAttributes Attributes
-Product_Id -Product_Id -Attribute_Id
-... -Attribute_Id -Attribute_Name
-Value -...
-...
Using as such:
SELECT p.Product_Id, a.Attribute_Name, pa.Value FROM Products p
JOIN ProductsAttributes pa ON pa.Product_Id = p.ProductId
JOIN Attributes a ON a.Attribute_Id = pa.Attribute_Id
Then you can reuse attributes, tie them to products, and store their values. Each product only has the attributes that it needs.

Multi/level query in MySQl - is an extra foreign key necessary?

Lets say that I have 3 tables:
departments, each of which has 0..n
jobs, each of which has 0..n
people
Given a department, how do I get all the people who work in that department? Can I do it with a single SELECT?
I have set up a fiddle with some sample data, but I can't formulate the correct query.
Can it be done with some JOIN magic? Or do I need to add a foreign key in the peeps table, pointing back to the department_id?
A simple join
SELECT people.*
FROM departments
INNER JOIN jobs ON departments.deperatment_id = jobs.deperatment_id
INNER JOIN people ON jobs.job_id = people.job_id
WHERE departments.deperatment_id = 1
You will need to amend the column names in the join conditions to the ones used in your tables.
Note that your sample tables on SQL fiddle do not have any indexes. Adding these is VERY important for performance.

SQL - Joining tables BUT not always

I need to perform a query SELECT that joins three tables (no problem with that). Nonetheless, the third table can, or NOT, have any element that match the joining KEY.
I want ALL data from the first two tables and if the ITEMS have ALSO information in the third table, fetch this data to.
For example, imagine that the first table have a person, the second table have his/her address (everyone lives anywhere), the third table stores the driving license (not everyone has this) - but I need to fetch all data whether or not people (all people) have driving license.
Thanks a lot for reading, if possible to give you suggestion / solution!
Use LEFT JOIN to join the third table. Using INNER JOIN a row has to exists. Using LEFT JOIN, the 'gaps' will be filled with NULLs.
SELECT
p.PersonID, -- NOT NULL
-- dl.PersonID, -- Can be null. Don't use this one.
p.FirstName,
p.LastName,
a.City,
a.Street,
dl.ValidUntilDate
FROM
Person p
INNER JOIN Addresse a ON a.AddressID = p.HomeAddressID
LEFT JOIN DrivingLicence dl ON dl.PersonId = p.PersonID

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.

Multiple tables in one view?

Today my question is how would I go about creating a view in a MySQL database that uses more than two tables?
Here is my query (it works) I am not looking to change my current query, mostly looking for a nice reference with examples on this topic.
CREATE OR REPLACE VIEW vw_itemsPurchased AS
SELECT `tbl_buyers`.`fldPrimaryKey` as fldFKeyBuyer, `tbl_buyers`.`fldEmail` as fldBuyerEmail, `tbl_buyers`.`fldAddressStreet`, `tbl_buyers`.`fldAddressCity`, `tbl_buyers`.`fldAddressState`, `tbl_buyers`.`fldAddressZip`, `tbl_buyers`.`fldAddressCountry`, `fldPaymentCurrency`, `fldPaymentGross`, `fldPaymentStatus`, `fldReceiverEmail`, `fldTransactionId`
FROM `tbl_transactions` INNER JOIN `tbl_buyers`
ON `tbl_transactions`.`fldFKeyBuyer` = `tbl_buyers`.`fldPrimaryKey`
Thanks for your time!
To use more than two tables, you simply continue adding JOIN statements to connect foreign keys. Adapting your code to add an imaginary third table tbl_products might look like this:
CREATE OR REPLACE VIEW vw_itemsPurchased AS (
SELECT
tbl_buyers.fldPrimaryKey as fldFKeyBuyer,
tbl_buyers.fldEmail as fldBuyerEmail,
tbl_buyers.fldAddressStreet,
tbl_buyers.fldAddressCity,
tbl_buyers.fldAddressState,
tbl_buyers.fldAddressZip,
tbl_buyers.fldAddressCountry,
fldPaymentCurrency, fldPaymentGross,
fldPaymentStatus,
fldReceiverEmail,
fldTransactionId,
tbl_tproducts.prodid
FROM
tbl_transactions
INNER JOIN tbl_buyers ON tbl_transactions.fldFKeyBuyer = tbl_buyers.fldP
-- Just add more JOINs like the first one..
JOIN tbl_products ON tbl_products.prodid = tbl_transactions.prodid
In the above method, the first and second tables relate, and the first and third tables relate. If you have to relate table1->table2 and table2->table3, list multiple tables in the FROM and relate them in the WHERE. The below is just for illustration and doesn't make much sense, as you probably wouldn't have a customer id in the same table as a product price.
SELECT
t1.productid,
t2.price,
t3.custid
FROM t1, t2, t3
WHERE
-- Relationships are defined here...
t1.productid = t2.productid
AND t2.custid = t3.custid