Database design question - Performance needed - mysql

I created an inventory system which mostly is using a server-sided scripting language to do all the work. To try and get some performance gains I am looking to better design my database to try and minimizing the scripts.
I have a table named metal_part which has a one to one relationship with five other tables, basically the other tables are other parts, which those parts then have a one to one relationship with a few other tables.
When I query metal_part I need all the UPC numbers from each table, so its direct one to one relationships need to get their own information from their direct one to one relationship tables ect... Is it possible to make a huge query to build it all and put it in a form at like:
(###) - ####/##/##/## [a-z]
Using a query? or do I have to get all the information and concat it using a scripting language?
Thanks

You should be able to get all of the information you need using a standard join, and then, with the concat function appropriate to your database (see here http://www.1keydata.com/sql/sql-concatenate.html) you can form the string you want.

Your question is very vague.
I'm guessing you are talking about matching on a primary key called partnumber or something like that.
You can do this using a query like
SELECT mp.partnumber
, mp.UPC_number
, wp.UPC_number
, pp.UPC_number
FROM metal_parts mp
INNER JOIN wood_parts wp ON (wp.partnumber = mp.partnumber)
INNER JOIN plastic_parts pp ON (pp.partnumber = mp.partnumber)
WHERE mp.partnumber = '8874578127';
You can also do
SELECT mp.partnumber
, group_concat(mp.UPC_number) as metal_UPCs
, group_concat(wp.UPC_number) as wood_UPCs
, group(concat(pp.UPC_number) as plastic_UPCs
FROM metal_parts mp
INNER JOIN wood_parts wp ON (wp.partnumber = mp.partnumber)
INNER JOIN plastic_parts pp ON (pp.partnumber = mp.partnumber)
WHERE mp.partnumber = '8874578127'
GROUP BY mp.partnumber;
or
SELECT mp.partnumber
, concat_ws(','
, group_concat(mp.UPC_number)
, group_concat(wp.UPC_number)
, group(concat(pp.UPC_number)
) as UPCs_of_parts
FROM metal_parts mp
INNER JOIN wood_parts wp ON (wp.partnumber = mp.partnumber)
INNER JOIN plastic_parts pp ON (pp.partnumber = mp.partnumber)
WHERE mp.partnumber = '8874578127'
GROUP BY mp.partnumber;

Related

learning mysql, JOIN query

i'm a beginner on MYSQL db and i'm trying to play around with the query and relations.
i have created 2 tables, one is 'users' which contain the field staff_ID and the other is 'reports' which also contain the table field staff_ID of the user submitting the reports.
on the relations (see picture) i have connect the 2 staff id field.
every user can submit more than one reports, so i'm try to query and get only the reports of one users(staff_ID).
I understood i have to use the JOIN keyword in order to obtain the data..
i tried the following query but it gave me all the result for all the users.
SELECT u.staff_ID
, u.Name
, r.id_report_show
, r.date_report
FROM users u
JOIN reports r
ON r.staff_ID = u.staff_ID
but I would like to have the report only of one specific user like staff_ID = 04033
probably i understood wrong how this query JOIN work, i'm looking for some help.
Thanks
You are almost there. Your join is perfect. You just need a where clause.
SELECT users.staff_ID, users.Name, reports.id_report_show, reports.date_report
FROM `users` INNER JOIN reports ON reports.staff_ID = users.staff_ID
where users.staff_ID = 04033
Or you can also mention it within on clauses:
SELECT users.staff_ID, users.Name, reports.id_report_show, reports.date_report
FROM `users` INNER JOIN reports
ON reports.staff_ID = users.staff_ID and users.staff_ID = 04033
Since it's inner join both the query will produce same output. But for left join those might produce different result. It's a good practice to use where clause instead of mentioning the condition in on clause.

Big Query SQL. Combining tables with the same columns (No PK)

I'm trying to combine 3+ NOAA GSOD data tables to get the data together in one super table. The I am attempting to JOIN the stations table onto the resultant data and then filter by country.
I've been able to do this for just one table but not for more. Below is my attempt at modifying the code to achieve this. I tried several different modifications with no success :(
SELECT * FROM [bigquery-public-data:noaa_gsod.gsod2016] AS gsod2016,
[bigquery-public-data:noaa_gsod.gsod2015] AS gsod2015 JOIN [bigquery-public-
data:noaa_gsod.stations] AS stations ON gsod2016.stn = stations.USAF AND
gsod2015.stn = stations.USAF WHERE stations.country = "CB"
NOAA GSOD bigquery data:
https://bigquery.cloud.google.com/table/bigquery-public-data:noaa_gsod.gsod2016
Use 1 standard inner join or , (preferably inner join syntax) and ensure the tables are in the correct order, you can't join on a table unless its' been defined above the ON.
SELECT *
FROM [bigquery-public-data:noaa_gsod.stations] AS stations
INNER JOIN [bigquery-public-data:noaa_gsod.gsod2016] AS gsod2016
ON gsod2016.stn = stations.USAF
INNER JOIN [bigquery-public-data:noaa_gsod.gsod2015] AS gsod2015
ON gsod2015.stn = stations.USAF
WHERE stations.country = "CB"
Now all this said did you really mean a join or did you want to UNION ALL
the data and add a year

Single SQL query on many to many relationship

I have a simple database with few tables (and some sample columns):
game (gm_id , game_name , company , desc)
plateform_master (p_id , plateform_name)
plateform_details (pd_id, gm_id, p_id, release_date)
Is there a way to create single SQL query which will return all game details with multiple plateform
Your question is not very clear. To which posts and categories are you referring yourself?
Here an example based on what I understood: Select all records from plateform_master and, for each of them, get its details from plateform_details. You can uncomment the where part in order to get one master record with its details. ("--" means comment in SQL)
select
pm.p_id
pd.*
from plateform_master as pm
inner join plateform_details as pd on pm.p_id = pd.p_id
-- where pm.p_id = 123
Sorry, my bad, it should be left join, not inner join!
With your changed requirements try this (not tested): Select all games and, for each one, get it's plateform_details and plateform_master correspondent values:
select
gm.gm_id,
gm.game_name,
gm.company,
pd.release_date,
pm.plateform_name
from game as gm
left join plateform_details as pd on pd.gm_id = gm.gm_id
left join plateform_master as pm on (pm.p_id = pd.p_id AND pd.gm_id = gm.gm_id)
-- WHERE CONDITIONS
;
Thanks for voting. I also wanted to tell you, that you have no many-to-many relationships here. You have just one-to-many. Many-to-many means the use of a middle table between two other ones.

MYSQL query issue - join product details into result

I want to get some data out of my database that is similar to a receipt you get at the supermarket (just an example which suits kinda good to my real situation).
For example you get the 2 (always only 2) products 1 and 3. These products are stored in a seperated product database.
Your shopping result is stored in one database containing all the details like time, location and so on AND in 2 columns (product_1, and product_2). Again this shopping situation is only a comparison to my real situation so I know that this would not be a good database structure for a shopping list.
So now I would like to get the Whole receipt but instead of printing the product IDs I would like to have the Name and for example the price on it.
If I had only one product I would use this query:
SELECT `list`.`time`, `list`.`location`, `prod`.`prod_name`, `prod`.`prod_price`
FROM `shopping_list` `list`, `products` `prod`
WHERE `list`.`product_1` = `prod`.`prod_id`
But since I have two products I cannot just go on with
AND `list`.`product_2` = `prod`.`prod_id`
But how do you achive what I would like to have?
Thank you very much,
Phil
You'll need to join to the product table twice
e.g.
SELECT
`list`.`time`,
`list`.`location`,
`prod1`.`prod_name` `prod_name1`,
`prod1`.`prod_price` `prod_price1` ,
`prod2`.`prod_name` `prod_name2`,
`prod2`.`prod_price` `prod_price2`
FROM `shopping_list` `list`
INNER JOIN `products` `prod1`
ON `list`.`product_1` = `prod1`.`prod_id`
INNER JOIN `products` `prod2`
ON `list`.`product_2` = `prod2`.`prod_id`
I'm not sure what your business rules are so you may need to convert the second INNER JOIN to a LEFT JOIN if they need to always select two products.
i don't know your exact situation but usually field names like product_1 and product_2 indicate bad database design. however if you really need that you need to join the products table twice.
select
*
from
list l
, product p1
, product p2
where
l.product_1 = p1.product_id
and l.product_2 = p2.product_id
(this is oracle syntax but i think it will work also in mysql).
hth.
The previous answers work well if you can parse out the two lines from 1 database result row. If you want two lines from the database you could do a UNION query:
SELECT `list`.`time`, `list`.`location`, `prod`.`prod_name`, `prod`.`prod_price`
FROM `shopping_list` `list`, `products` `prod`
WHERE `list`.`product_1` = `prod`.`prod_id`
UNION
SELECT `list`.`time`, `list`.`location`, `prod`.`prod_name`, `prod`.`prod_price`
FROM `shopping_list` `list`, `products` `prod`
WHERE `list`.`product_2` = `prod`.`prod_id`

Multiple data stored into a field for better management?

I have a MySQL table as follow:
id, user, culprit, reason, status, ts_register, ts_update
I was thinking of using the reason as an int field and store just the id of the reason that could be selected by the user and the reason itself could be increased by the admin.
What I meant by increased is that the admin could register new reason, for example currently we have:
Flood, Racism, Hacks, Other
But the admin could add a new reason for instance:
Refund
Now my problem is that I would like to allow my users to select multiple reasons, for example:
The report 01 have the reasons Flood and Hack.
How should I store the reason field so that I could select multiple reasons while maintaining a good table format?
Should I just go ahead and store it as a string and cast it as an INT when I am searching thru it or there are better forms to store it?
UPDATE Based on Jonathan's reply:
SELECT mt.*, group_concat(r.reason separator ', ') AS reason
FROM MainTable AS mt
JOIN MainReason AS mr ON mt.id = mr.maintable_ID
JOIN Reasons AS r ON mr.reason = r.reason_id
GROUP BY mt.id
The normalized solution is to have a second table containing one row for each reason:
CREATE TABLE MainReasons
(
MainTable_ID INTEGER NOT NULL REFERENCES MainTable(ID),
Reason INTEGER NOT NULL REFERENCES Reasons(ID),
PRIMARY KEY(MainTable_ID, Reason)
);
(Assuming your main table is called MainTable and you have a table defining valid reason codes called Reasons.)
From a comment:
[W]ould you be [so] kind [as] to show me an example of selecting something to retrieve a report's reason? I mean if I simple select it SELECT * FROM MainTABLE I would never get any reasons since MainTable doesnt know it right? Because it is only linked to the MainReasons and Reasons table so I would need to do something like SELECT * FROM MainTable LEFT JOIN MainReasons USING (MainTable_ID) or something alike but how would I go about getting all the reasons if multiples?
SELECT mt.*, r.reason
FROM MainTable AS mt
JOIN MainReason AS mr ON mt.id = mr.maintable_ID
JOIN Reasons AS r ON mr.reason = r.reason_id
This will return one row per reason - so it would return multiple rows for a single report (recorded in what I called MainTable). I omitted the reason ID number from the results - you can include it if you wish.
You can add criteria to the query, adding terms to a WHERE clause. If you want to see the reports where a specific reason is specified:
SELECT mt.*
FROM MainTable AS mt
JOIN MainReason AS mr ON mt.id = mr.maintable_ID
JOIN Reasons AS r ON mr.reason = r.reason_id
WHERE r.reason = 'Flood'
(You don't need the reason in the results - you know what it is.)
If you want to see the reports where 'Floods' and 'Hacks' were the reasons given, then you can write:
SELECT mt.*
FROM MainTable AS mt
JOIN (SELECT f.MainTable_ID
FROM (SELECT MainTable_ID
FROM MainReason AS mr1
JOIN Reasons AS r1 ON mr1.reason = r1.reason_ID
WHERE r1.reason = 'Floods'
) AS f ON f.MainTable_ID = mt.MainTable_ID
JOIN (SELECT f.MainTable_ID
FROM (SELECT MainTable_ID
FROM MainReason AS mr2
JOIN Reasons AS r2 ON mr2.reason = r2.reason_ID
WHERE r1.reason = 'Hacks'
) AS h ON h.MainTable_ID = mt.MainTable_ID
To do a one-to-many relationship, I would spin reason off into it's own table, like so:
id, parent_id, reason
parent_id would refer back into your current table's id.
You could store it as an INT, but it would be a continual pain to have to parse it every time you wanted to read the data. This way would just take one more join.