SQL difficult statement - mysql

Currently I'm looking for a solution. English is not my native language so I added two pictures to clarify it a bit. My knowledge of SQL is rather basic.
A chair (end-product) contains several components. Each component contains an item number, each spare set contains multiple item numbers. In the database a spare set is in the same table as an end-product. The chairs and spare parts are categorized in different groups.
Is it possible to create a table like that? If it's possible how?
Thanks in advance!

This would be my approach:
Table: Products -- a table of products
ProductID ProductName DateAdded
1 Chair X 01/01/2016
2 Chair Y 05/05/2016
3 Spare Set A 06/06/2016
...
Table: Components -- a table of components
ComponentID ComponentName ItemNumber DateAdded
1 Backrest X01 01/01/2016
2 Headrest X02 01/01/2016
...
Table: ProductComponent -- a lookup/mapping table to link Product and Component
PCID ComponentID ProductID DateAdded
1 1 1 01/01/2016
2 2 1 01/01/2016
...
DateAdded is the date the product or component was first entered into the database. It is for audit purposes.

Related

1NF, 2NF, AND 3NF Normalization?

I have a teacher who doesn't like to explain to the class but loves putting up review questions for upcoming tests. Can anyone explain the image above? My main concern in the red underline which shows that supplier and supplierPhone are repeated values. I thought that repeated values occurred when there were many occurrences of the same item in a column.
Another question I have is that if the Supplier is a repeating value, why isnt Part_Name a repeating value because they both have 2 items with same names in their columns.
Example:
It's repeated because the result of the tuple is always the same. E.g. ABC Plastics will always have the same phone number, therefore having 2 rows with ABC Plastics means that we have redundant information in the phone number.
Part1 Company1 12341234
Part2 Company1 12341234
We could represent the same information with:
Part1 Company1
Part2 Company1
And
Company1 12341234.
Therefore having two rows with the same phone number is redundant.
This should answer your second question as well.
Essentially you're looking for tuples such that given the tuple (X, Y) exists, if there exists another tuple (X, Y') then Y' = Y
Looks like five tables to me.
model (entity)
modelid description price
1 Laserjet 423.56
1 256 Colour 89.99
part (entity)
partid name
PF123 Paper Spool
LC423 Laserjet cartridge
MT123 Power supply
etc
bill_of_materials (many to many relationship model >--< part )
modelid partid qty
1 PF123 2
1 LC423 4
1 MT123 1
2 MT123 2
supplier (entity)
supplier_id phone name
1 416-234-2342 ABC Plastics
2 905.. Jetson Carbons
3 767... ACME Power Supply
etc.
part_supplier (many to many relationship part >--< supplier )
part_id supplier_id
PF123 1
LC423 2
MT123 3
etc.
You have one row in model, part, supplier for each distinct entity
You have rows in bill_of_materials for each part that goes into each model.
You have a row in part_supplier for each supplier that can furnish each part. Notice that more than one part can come from one supplier, and more than one supplier can furnish each part. That's a many-to-many relationship.
The trick: Figure out what physical things you have in your application domain. Then make a table for each one. Then figure out how they relate to each other (that's what makes it relational.)

sql store the data in the column wise

id user_id apt_id name value datetime
1 1 1 bp 109 ....
2 1 1 sugar 180 ....
3 2 2 bp 170 ....
I am trying to create the table in this approach because, the patient column is not the standard one, sometimes patient will be store the bp and sugar, sometime only bp.
Am i right in creating the design. If right, how to get the records of single patient.
Thanks,
If am not wrong, userid is your patientid in your scenario, in that case, use the below query to get the single patient record,
select * from Patienttable where user_id = '1'
Here you will get the single patient record. i.e., for user_id = 1
Output:
id user_id apt_id name value datetime
1 1 1 bp 109 ....
2 1 1 sugar 180 ....
Note: You can change as you want instead of 1
Others may disagree, but I wouldn't do it this way, unless you had several changing symptoms that you collect at different appointments. If it's a small collection (some of which are not collected), I would just add them as columns to the appointment table, and leave the sugar column as NULL when it's not collected.
user_id apt_id bp sugar datetime
1 1 109 180 ....
2 1 170 ....
The model you're proposing is a variant of Entity-Attribute-Value design, which has some strengths and some weaknesses. Aaron Bertrand had a good writeup of when an EAV design is useful, and what the costs are for that design. Based on the scenario you described, I don't think it's the best fit.

Match between two tables where field is substring of the other

Hi (sorry for the poor title),
I have two tables in a MySQL DB, lets call them CarMake and CarModel. Both tables have two fields, ID:int(11) and Description:varchar(100). For example:
CarMake CarModel
ID Description | ID Description
-----------------------------------------------------
123456 Honda | 12345678 Accord
234567 Toyota | 12345665 Civic
369258 Lexus | 23456789 Prius
Where each car model shares the same first 6 digits of the ID of its Make. In this example, both Accord and Civic share the first 6 digits of the ID with Honda, therefore they are Honda models.
Now, what I want to do is select all rows from CarMake that do not have a record in CarModel where the first 6 digits of the ID match. In this example, my query should return the Lexus row from CarMake, as it does not have a matching row in CarModel.
Nothing I have tried so far has really come close to achieving what I want, so I am posting it here.
Any help would be greatly appreciated!
EDIT: Solved with help from zerkms
SELECT * FROM CarMake
LEFT JOIN CarModel
ON CarModel.ID LIKE CONCAT(CarMake.ID, '%')
WHERE CarModel.ID IS NULL;
Follow up questions:
This solution takes a very long time to run, is there any way to improve efficiency?
What would be the best way to delete the records returned by that query? Is there some way I can combine that into the query itself?

SQL "shortcut" identifiers or a long string of joins?

QUESTION: Is it okay to have "shortcut" identifiers in a table so that I don't have to do a long string of joins to get the information I need?
To understand what I'm talking about, I'm going to have to lay ouf an example here that looks pretty complicated but I've simplified the problem quite a bit here, and it should be easily understood (I hope).
The basic setup: A "company" can be an "affiliate", a "client" or both. Each "company" can have multiple "contacts", some of which can be "users" with log in privileges.
`Company` table
----------------------------------------------
ID Company_Name Address
-- ----------------------- -----------------
1 Acme, Inc. 101 Sierra Vista
2 Spacely Space Sprockets East Mars Colony
3 Cogswell Cogs West Mars Colony
4 Stark Industries Los Angeles, CA
We have four companies in our database.
`Affiliates` table
---------------------
ID Company_ID Price Sales
-- ---------- ----- -----
1 1 50 456
2 4 50 222
3 1 75 14
Each company can have multiple affiliate id's so that they can represent the products at different pricing levels to different markets.
Two of our companies are affiliates (Acme, Inc. and Stark Industries), and Acme has two affiliate ID's
`Clients` table
--------------------------------------
ID Company_ID Referring_affiliate_id
-- ---------- ----------------------
1 2 1
2 3 1
3 4 3
Each company can only be a client once.
Three of our companies are clients (Spacely Space Sprockets, Cogswell Cogs, and Stark Industries, who is also an affiliate)
In all three cases, they were referred to us by Acme, Inc., using one of their two affiliate ID's
`Contacts` table
-----------------------------------------
ID Name Email
-- -------------- ---------------------
1 Wylie Coyote wcoyote#acme.com
2 Cosmo Spacely boss#spacely.com
3 H. G. Cogswell ceo#cogs.com
4 Tony Stark tony#stark.com
5 Homer Simpson simpson#burnscorp.com
Each company has at least one contact, but in this table, there is no indication of which company each contact works for, and there's also an extra contact (#5). We'll get to that in a moment.
Each of these contacts may or may not have a login account on the system.
`Contacts_type` table
--------------------------------------
contact_id company_id contact_type
---------- ---------- --------------
1 1 Administrative
2 2 Administrative
3 3 Administrative
4 4 Administrative
5 1 Technical
4 2 Technical
Associates a contact with one or more companies.
Each contact is associated with a company, and in addition, contact 5 (Homer Simpson) is a technical contact for Acme, Inc, and contact 4 (Tony Stark) is a both an administrative contact for company 4 (Stark Industries) and a technical contact for company 3 (Cogswell Cogs)
`Users` table
-------------------------------------------------------------------------------------
ID contact_id company_id client_id affiliate_id user_id password access_level
-- ---------- ---------- --------- ------------ -------- -------- ------------
1 1 1 1 1 wylie A03BA951 2
2 2 2 2 NULL cosmo BF16DA77 3
3 3 3 3 NULL cogswell 39F56ACD 3
4 4 4 4 2 ironman DFA9301A 2
The users table is essentially a list of contacts that are allowed to login to the system.
Zero or one user per contact; one contact per user.
Contact 1 (Wylie Coyote) works for company 1 (Acme) and is a customer (1) and also an affiliate (1)
Contact 2 (Cosmo Spacely) works for company 2 (Spacely Space Sprockets) and is a customer (2) but not an affiliate
etc...
NOW finally onto the problem, if there is one...
Do I have a circular reference via the client_id and affiliate_id columns in the Users table? Is this a bad thing? I'm having a hard time wrapping my head around this.
When someone logs in, it checks their credentials against the users table and uses users.contact_id, users.client_id, and users.affiliate_id to do a quick look up rather than having to join together a string of tables to find out the same information. But this causes duplication of data.
Without client_id in the users table, I would have to find the following information out like this:
affiliate_id: join `users`.`contact_id` to `contacts_types`.`company_id` to `affiliates`.`company_id`
client_id: join `users`.`contact_id` to `contacts_types`.`company_id` to `clients`.`company_id`
company_id: join `users`.`contact_id` to `contacts_types`.`company_id` to `company`.`company_id`
user's name: join `users`.`contact_id` to `contacts_types`.`contact_id` to `contacts`.`contact_id` > `name`
In each case, I wouldn't necessarily know if the user even has an entry in the affiliate table or the clients table, because they likely have an entry in only one of those tables and not both.
Is it better to do these kinds of joins and thread through multiple tables to get the information I want, or is it better to have a "shortcut" field to get me the information I want?
I have a feeling that over all, this is overly complicated in some way, but I don't see how.
I'm using MySQL.
it's better to do the joins. you should only be denormalizing your data when you have timed evidence of a slow response.
having said that, there are various ways to reduce the amount of typing:
use "as" to give shorter names to your fields
create views. these are "virtual tables" that already have your standard joins built-in, so that you don't have to repeat that stuff every time.
use "with" in sql. this lets you define something like a view within a single query.
it's possible mysql doesn't support all the above - you'll need to check the docs [update: ok, recent mysql seems to support views, but not "with". so you can add views to do the work of affiliate_id, client_id etc and treat them just like tables in your queries, but keeping the underlying data nicely organised.]

e-commerce structure for products (MySQL)

I am considering how to structure my MySQL database in e-commerce solution. To be more specific I am looking at the product structure.
These are the tables I have come up with so far. What do you think?
Explanation of structure
The application is multilingual. Therefore the product table are split in 2 tables.
If a products has e.g. 2 variants (Small, Medium) a total of 3 rows will be inserted. This is because each variant can have different information for each variant. When the product is shown on the webpage product 1 will be shown with a drop down box with Small & Medium. A product with no variants will naturally only insert 1 row.
products
id master product_number
1 0 123
2 1 456
3 1 678
products_descriptions
id product_id country_code image name description vat price
1 1 en-us image.jpg t-shirt Nice t-shirt 25 19.99
2 2 en-us image.jpg t-shirt Nice t-shirt 25 19.99
3 3 en-us image.jpg t-shirt Nice t-shirt 25 19.99
products_to_options
product_id option_id
2 1
3 2
options
id name
1 Small
2 Medium
Your Products table is schizophrenic, its entity is sometimes Product and sometimes Variant. This leads to very cumbersome behavior. For example, you'd like the question "how many different products do we have?" be answered by select count(*) from products, but here this gives the wrong answer, to get the correct answer you have to know the Magic Number 0 and query select count (*) from products where master=0. "List all products and how many variants we have for each" is another query that should be straightforward but now isn't. There are other anomalies, like the fact that the first line in products_descriptions is a shirt that has a price and a picture but no size (size is stored in the variants, but they have prices and pictures of their own).
Your problem sounds like you have products in two contexts: (1) something that can be displayed as an item in your store, and (2) something that can be ordered by your customer. (1) probably has a name like "Halloween T-Shirt" or so, and it probably has an image that the customer sees. (2) is what the customer orders, so it has a (1), but also a variant specification like "small" or maybe a color "red". It probably has a price, too, and an order_id so your shop can know what specific item to ship.
You should give each context an entity. Here's how i'd do it
displayable_product
id name
1 "Baseball Cap"
2 "T-Shirt"
orderable_product
id d_product_id order_id size color price
1 1 123 red 9.99
2 2 456 small 19.99
3 2 789 medium 21.99
displayable_content
id d_product_id locale name image
1 1 en_US "Baseball Cap" baseballcap.jpg
2 1 es_US "Gorra de Beisbol" baseballcap.jpg
3 2 en_US "Nice T-Shirt" nicetshirt.jpg
4 2 es_US "Camiseta" nicetshirt.jpg
You should probably use locale instead of country in the display tables to account for countries with more than one language (USA, Switzerland, and others), and you might separate the size and color into its own variants table. And if you need country-dependent data on the orderables (like different prices/currencies for shipping to different countries), you'd have to extract a country-dependent orderable_content table, too.