SQL Multi-Location inventory DB - mysql

I am creating a DB where in one table it holds store location information like location ID, address info, and a column for the inventory:
Location_ID
paint_inventory
address info
1001
red,blue,black
address stuff
1002
blue,orange
address stuff
The database also has a table that gives each paint an ID:
paint_ID
color_name
1
red
2
blue
3
purple
4
black
5
orange
How can I efficiently store this information where the location table looks like this (using an ID to reference the color info in the other table):
Location_ID
paint_inventory
address info
1001
1,2,4
address stuff
1002
2, 5
address stuff
NOTE:
I have seen posts where people say storing information in a delimited string is poor practice, however, I am basically recreating an already existing DB and the first location table is how the data is formatted.
UPDATE:
To rephrase a little: how could I efficiently store the paint_inventory column? I was given the data as it is in the first table and my only thought of how to store this is the way I provided (Once again I understand you should never store data as a delimited string but this is how I was given the data)

You should create a joining table -- that table would look like this
id int -- unique generated id for relationship
paint_id int -- pointer to the paint
location_id int -- pointer to the location
I like to call the tables by the things they join ordered alphabetically so I would call this table location_paint
There might be additional information for a can of paint at a location you could put in this table -- how full it is, when it was purchased, when it was used up, etc.
There could also be meta data in the table -- when the record was created when it was edited, who created it -- etc.

Related

Storing List in Mysql [duplicate]

This question already has answers here:
Is storing a delimited list in a database column really that bad?
(10 answers)
Closed 3 years ago.
I want to store user information in Mysql for my Python Program.
One of the things I want to store is username history (static list)
Another is which groups they are a member of (dynamic list)
I am new to storing data in Mysql so am trying to figure out the best structure to achieve this. It seems like I could create 1 table for each user and have the name hsitory as a column, but everything I read tells me this would be wasteful and inefficient.
so for example....
Table = users
user_ID | current_username | username_history | groups_joined | groups_banned
========|==================|==================|===============|==============
01567 | Dave |Michael,Geoff, |group1,group2, |group4,group5
| |Bob,Nigel,Colin |group2 |group5,group7
========|==================|==================|===============|==============
01568 | Fred |Martin,Simon, |group3,group4, |group4,group3
| |Leo,Nick,Arthur |group6 |group2,group12
My first thought was to do something like the above and when I have a list to store like username_history I would convert the list to a string with comma seperated values and store it in a LONGTEXT field as shown. Then to add usernames as the user changes them I could use concat to add to the string.
This would work I guess, but it feels ugly and im sure there must be a better way. Also I think this would be very inefficient if I needed to search for a name in username history, find out all users that were called Fred for example.
My next thought was to create an entire table per user and populate the username_column with one name per field.
But googling around I found similar questions from database noobs all with replies saying this would create thousands of tables and be very inefficient.
ok so now im looking at relational tables (correct terminology??)....
table = username_history
user_id | usernames
========|==========
01567 | but I still need a list here....
I'm sure this is a very common problem for beginners, but I just can't seem to get my head around how the structure for my usage would look.
Thanks to anyone taking the time to help and advise :)
Create a table username_history with:
create table username_history (
id int not null auto_increment,
user_id varchar(10),
username varchar(30),
created_at datetime default CURRENT_TIMESTAMP,
primary key (`id`),
index (user_id)
);
You can then get the usernames in list format using GROUP_CONCAT-function.
You really need three tables:
Groups
Users
UserGroups
The first contains a list of the groups which user may join. It could be as simple as a unique ID and Group Name.
The second table is similar to your table in the question. For this purpose, the only columns we are concerned with are the unique ID for each user and their user name.
The third table has two columns: user_id and group_id. When a user joins a group, a row is inserted into this table with the unique IDs of the user and group.
You could also have a column with a timestamp of when the row was added, and a column for the user's status if needed.
The timestamp column would let you know when the user joined the group.
The status column could indicate if the user is banned from the group, or if the user left the group.

Store a unique reference to a Mysql Table

I am creating a site that is sort of ecommerce-ish. I want to give my users a perfect search ability using specific attributes that differ from product to product. I plan to create 1 products table storing the basic information that is shared among products i.e Name, Description, Price and a few others. Then I plan to create several "details" table say categories_computers with columns Processor, HDD, RAM, etc and another table say table_shoes with columns MATERIAL, SIZE, GENDER, etc.
I am new to Mysql but not to the concept of Databases. I don't think I will have a problem storing this data to each table. My issue comes about from reads. It won't be hard to query a product id but I think it would be extremely wasteful to query all details tables to get the details of the product since 1 product can only have 1 details.
So my question is how can I store a reference to a table in a column so that a product has say ID, Name, Description, Price, Details_Table_ID or something similar to save on queries. Do tables have unique ids in Mysql? Or how does the Stackoverflow community suggest I go about this? Thanks.
EDIT
Silly me, I have just remembered that every table name is uniques so I can just use that, so my question changes to how I can write a query that contains one cell in a table A to be used as a reference to a Table name.
Don't use separate details tables for each category, use a generic details table that can store any attribute. Its columns would be:
Product_ID INT (FK to Products)
Attribute VARCHAR
Value VARCHAR
The unique key of this table would be (Product_ID, Attribute).
So if Product_ID = 1 is a computer, you would have rows like:
1 Processor Xeon
1 RAM 4GB
1 HDD 1TB
And if Product_ID = 2 is shoes:
2 Material Leather
2 Size 6
2 Gender F
If you're worried about the space used for all those attribute strings, you can add a level of indirection to reduce it. Create another table Attributes that contains all the attribute names. Then use AttributeID in the Details table. This will slow down some queries because you'll need to do an additional join, but could save lots of space
Think about just having a single ProductDetails table like this:
ProductDetailID (PK)
ProductID (foreign key to your Products table)
DetailType
DetailValue
this way you do not have to create new columns every time you add a new product detail type. and you'll have many ProductDetail rows for each productid, which is fine and will query ok. Just be sure to put an index on ProductDetails.ProductID !
Since this is an application so you must be generating the queries. So lets generate it in 2 steps. I assume you can add a column product_type_id in your Product table that will tell you which child table to user. Next create another table Product_type which contains columns product_type_id and query. This query can be used as the base query for creating the final query e.g.
Product_type_id | Query
1 | SELECT COMPUTERS.* FROM COMPUTERS JOIN PRODUCT ON COMPUTERS.PRODUCT_ID = PRODUCT.PRODUCT_ID
2 | SELECT SHOES.* FROM SHOES JOIN PRODUCT ON COMPUTERS.PRODUCT_ID = PRODUCT.PRODUCT_ID
Based on the product_id entered by the user lookup this table to build the base query. Next append your where clause to the query returned.

Create a new lookup table where data already exists

I am working on a database in MS Access 2013 which has a considerable amount of non-normalised data, and I want to move them out to alternate tables and use them as lookups in the main table. However, when I create a lookup column, MS Access deletes the data and there is far too much data to reset every record by hand.
Is there a way in Access 2013 to create such a lookup without losing the data?
Please don't comment about how using lookup tables in Access is bad. I have read posts like the one below and I disagree with most of the points there, and some of them are just simply wrong.
http://access.mvps.org/access/lookupfields.htm
Below is a sample of my data. I need to extract the 2nd and 3rd fields to other tables. If I can do this with them, I can do it with the others.
Presently this is stored as text in the fields. I would like to remove them and replace them with FK id's.
You could create your second table and add the data to the table. Then update the first table to match the records to each other
Let say you have the following table:
CustOrders
ID Customer DateOrdered
123 K-Mart 01/01/2013
124 K Mart 01/05/2013
125 Walmart 02/05/2013
126 Walmart 03/07/2013
127 Miejers 03/11/2013
128 K-Mart 03/12/2013
You could find out all of the Customers that are in the CustOrders table by performing the following:
SELECT DISTINCT Customer From CustOrders
Then create a record in the following table for each:
Customers
ID Customer
1 K-Mart
2 Walmart
3 Miejers
Then you could Update the CustOrders table by performing the following:
UPDATE CustOrders SET Customer = 1 WHERE Customer = 'K-Mart' OR Customer = 'K Mart'
Of course you would have to do this for each distinct customer you have.
Then if you want you could change the data type of the Customer field in the CustOrders table to Long Integer.
Lastly I would create a combo box on any entry/edit form that has the following RowSource:
SELECT ID, Customer FROM Customers ORDER BY Customer
Set the combo box to limit from list and bind to column 1.

Database table design - are my fields correct?

I need to sell items on my fictitious website and as such have come up with a couple of tables and was wondering if anyone could let me know if this is plausible and if not where i might be able to change things?
I am thinking along the lines of;
Products table : ID, Name, Cost, mediaType(FK)
Media: Id, Name(book, cd, dvd etc)
What is confusing me is that a user might have / own many products, but how would you store an array of product id's in a single column?
Thanks
You could something like store a JSON array in a text or varchar field and let the application handle parsing it.
MySQL doesn't have a native array type, unlike say PostgreSQL, but in general I find if you're trying to store an array you're probably doing something wrong. Of course every rule has its exceptions.
What your probably want is a user table and then a table that correlates products to users. If a product is only going to relate to one user then you can add a user ID column to your Products table. If not, then you'll want another lookup table which handles the many to many relationship. It would look something like this:
------------------------
| user_id | product_id |
------------------------
| 1 | 1 |
| 1 | 2 |
| 1 | 3 |
| 2 | 2 |
| 3 | 1 |
| 3 | 5 |
------------------------
I think one way of storing all the products which user has in one column is to store it as a string where product ids are separated by some delimiters like comma. Though this is not the way you want to solve. The best way to solve this problem would be to have a seperate user table and than have a user product table where you associate userid with product id. You could than simple use a simple query to get list of all the products owned by a particular userid
As a starting point, try to think of the system in terms of the major parts - you would have a 'warehouse', so you need a table to list the products you have, and you are going to possibly have users who register their details with you for regular visits - so an account per user. You would generally hold all details of a single product in the same row of the same table (unless you have a really complex product to detail, but not likely). If you're going to keep track of products bought per user account, there's always the option of keeping the order history as a delimited list in a large text field. For example: date,id,id,id,id;date,id,id. Or you could simply refer to order numbers and have a separate table for orders placed [by any customer].
What is confusing me is that a user might have / own many products, but how would you store an array of product id's in a single column?
This is called a "many-to-many" relationship. In essence you would have a table for users, a table for products, and a table to map them like this:
[table] Users
- id
- name
[table] Products
- id
- name
- price
[table] Users_Products
- user_id
- product_id
Then when you want to know what products a user has, you could perform a query like:
SELECT product_id FROM Users_Products WHERE user_id=23;
Of course, user id 23 is fictituous for examples sake. The resulting recordset would contain the id's of all the products the user owns.
You wouldn't store an array of things into a single column. In fact you usually wouldn't store them in separate columns either.
You need to step away from design for a bit and go investigate third normal form. That should be you starting point and, in the vast majority of cases, your ending point for designing database schemas.
The correct way of handling variable size "arrays" is with two tables with a many to one relationship, something like:
Users
User ID (primary key)
Name
Other user info
Objects:
Object Id (primary key)
User id (foreign key, references Users(User id)
Other object info
That's the simplest form where one object is tied to a specific user, but a specific user may have any number of objects.
Where an object can be "owned" by multiple users (I say an object meaning (for example) the book "Death of a Salesman", but obviously each user has their own copy of an object), you use a joining table:
Users
User ID (primary key)
Name
Other user info
Objects:
Object Id (primary key)
User id (foreign key, references Users(User id))
Other object info
UserObjects:
User id (foreign key, references Users(User id))
Object id (foreign key, references Objects(Object id))
Count
primary key (User id, Object id)
Similarly, you can handle one or more by adding an object id to the Users table.
But, until you've nutted out the simplest form and understand 3NF, they won't generally matter to you.

Handling custom user fields with possibility of grow and shrink

This question is much about how to do, idea etc.
I have a situation where a user can create as many custom fields as he can of type Number, Text, or Date, and use this to make a form. I have to make/design some table model which can handle and store the value so that query can be done on these values once saved.
Previously I have hard coded the format for 25 user defined fields (UDF). I make a table with 25 column with 10 Number, 10 Text, and 5 Date type and store the label in it if a user makes use of any field. Then map it to other table which has same format and store the value. Mapping is done to know which field is having what label but this is not an efficient way, I hope.
Any suggestion would be appreciated.
Users have permissions for creating any number of UDF of the above types. then it can be used to make forms again this is also N numbers and have to save the data for each form types.
e.g. let's say a user created 10 number 10 date and 10 text fields used first 5 of each to make form1 and all 10 to make form2 now saved the data.
My thoughts on it:
Make a table1 with [id,name(as UDF_xxx where xxx is data type),UserLabel ]
table2 to map form and table1 [id(f_key table1_id), F_id(form id)]
and make 1 table of each data type as [ id(f_key of table1),F_id(form number),R_id(row id for data, would be same for all data type),value]
Thanks to all I'm going to implement, it both DataSet entry and json approach looks good as it gives wider extension-ability. Still I've to figure out which will best fit with the existing format.
There are two approaches I have used.
XML: To create a dynamic user attribute, you may use XML. This XML will be stores in a clob column - say, user_attributes. Store the entire user-data in XML key-value pair, with type as an attribute or another field. This will give you maximum freedom. You can use XOM or any other XML object Model API to display or operate on the data. A typical Node will look like
<userdata>
...
...
<datanode>
<key type="Date">User Birth</key>
<value>1994-02-25</value>
</datanode>
...
</userdata>
Attribute-AttributeValue This is same thing as above but using tables. What you do is you create a table -- attributes with FK as user_id, another table attribute_values with FK as attribute_id. attributes contains multiple field-names and types for each user and attribute_values contains values of those attributes. so basically,
users
user_id
attributes
attr_id
user_id (FK)
attr_type
attr_name
attribute_values
attr_val_id
attr_id (FK)
attr_val
If you see in both the approached you are not limited by how-many or what type of data you have. But there is a down-side of this is parsing. In either of the case, you will have to to do a small amount of processing to display or analyze the data.
The best of both worlds (having rigid column structure vs having completely dynamic data) approach is to have a users table with must-have columns (like user_name, age, sex, address etc) and have user-created data (like favorite pet house etc.) in either XML or attribute-attribute_value.
What do you want to achieve?
A table per form permutation or might each dataset consist of different sets?
Two possibilities pop into my mind:
Create a table that describes one field of a dataset, i.e. the key might be dataset id + field id and additional columns could contain the value stored as a string and the type of that value (i.e. number, string, boolean, etc.).
That way each dataset might be different but upon reading a dataset and storing it into an object you could create the appropriate value types (Integer, Double, String, Boolean etc.)
Create a table per form, using some naimg convention. When the form layout is changed, execute ALTER TABLE statements to add, remove, rename columns or change their type.
When the user changes the type of a column or deletes it, you might need to either deny that if the values are not null or at least ask the user if she's willing to drop values that don't match the new requirements.
Edit: Example for approach 1
Table UDF //describes the available fields--------
id (PK)
user_id (FK)
type
name
Table FORM //describes a form's general attributes--------
id (PK)
user_id (FK)
name
description
Table FORM_LAYOUT //describes a form's field layout--------
form_id (FK)
udf_id (FK)
mapping //mapping info like column index, form field name etc.
Table DATASET_ENTRY //describes one entry of a dataset, i.e. the value of one UDF in
--------
id (PK)
row_id
form_id (FK)
udf_id (FK)
value
Selecting the content for a specific form might then be done like this:
SELECT e.value, f.type, l.mapping from DATASET_ENTRY e
JOIN UDF f ON e.udf_id = f.id
JOIN FORM_LAYOUT l ON e.form_id = l.form_id AND e.udf_id = l.udf_id
WHERE e.row_id = ? AND e.form_id = ?
Create a table which manages which fields exist. Then create tables for each data type you want to support, where the user will their values into.
create table Fields(
fieldid int not null,
fieldname text not null,
fieldtype int not null
);
create table FieldDate
(
ValueId int not null,
fieldid int not null,
value date
);
create table FieldNumber
(
ValueId int not null,
fieldid int not null,
value number
);
..
Another possibility would be to use ALTER TABLE to create custom fields. If your application has the rights to perform this command and the custom fields are changing very rarely this would be the option I chose.