MySQL: Unique combination key if field is blank/zero/null - mysql

I have a simple database table which I'd like to keep simple (instead of breaking it into 3-5 smaller ones). For simplicity's sake, here's what it looks like, with a few sample entries:
+----------+-----------+----------+--------+
| memberId | guestName | guestAge | date |
+----------+-----------+----------+--------+
| 123 | | | 1/2/13 |
+----------+-----------+----------+--------+
| | Bob | 30 | 1/2/13 |
+----------+-----------+----------+--------+
What I'm wondering: is there a way to enforce unique pairing of memberIds and dates, but not forcing guestNames or ages?
Notes:
We could have multiple guests named Bob, age 30 on 1/2/13, thereby making a unique key across all the fields not a workable solution.
I realize I could split the guests and members into separate tables, but this significantly complicates the rest of the problem (which I have left off already to simplify). It's simply not worth it at this point.
So my question: is this possible, or an (understandable) limitation of the MySQL unique key?

Related

MySQL - Multiple Rows or JSON

I'm building an app in Laravel and have a design question regarding my MySQL db.
Currently I have a table which defines the skills for all the default characters in my game. Because the traits are pulled from a pool of skills, and have a variable number, one of my tables looks something like this:
+----+--------+---------+-----------+
| ID | CharID | SkillID | SkillScore|
+----+--------+---------+-----------+
| 1 | 1 | 15 | 200 |
| 2 | 1 | 16 | 205 |
| 3 | 1 | 12 | 193 |
| 4 | 2 | 15 | 180 |
+----+--------+---------+-----------+
Note the variable number of rows for any given CharID. With my Base Characters entered, I'm at just over 300 rows.
My issue is storing User's copies of their (customized)characters. I don't think storing 300+ rows per user makes sense. Should I store this data in a JSON Blob in another table? Should I be looking at a NoSQL solution like Mongo? Appreciate the guidance.
NB: The entire app centers around using the character's different skills. Mostly reporting from them, but users will also be able to update their SkillScore (likely a few times a week).
ps. Should I consider breaking each character out into their own table and tracking user's characters that way? Users won't be able to add/remove the skills from characters, only update them.
TIA.
Your pivot table looks good to me.
I'd consider dropping the ID column (unless you need it), and using a composite primary key:
PRIMARY_KEY(CharID, SkillID)
Primary keys are indexed so you will get efficient lookups.
As for your other suggestions, if you store this in a JSON column, you'll lose the ability to perform joins, and will therefore end up executing more queries.

Over 2500 tables in mysql

My application stores login information of over 2500 employees in a table named "emp_login".
Now I have to store the activities of every employee on daily basis. For this purpose i have created a separate table for every employee. E.g. emp00001, emp0002... Each table will have about 50 columns.
After digging in alot on stackoverflow I'm kind of confused. Many of the experts say that database having more than 200-300 tables on mysql is considered to be poorly designed.
My question is whether it is good idea to have such a bulk of tables? Is my database poorly designed? Should i choose other database like mssql? Or some alternative idea is there to handle the database of such applications??
Do -not- do it that way. Every employee should be in 1 table and have a primary key index ID ie:
1: Tom
2: Pete
You then assign the actions with a column that references the employees ID number
Action, EmployeeID
You should always group identical entities in a table with index ids and then link properties / actions to those entities by Id. Imagine what you would have to do to search a database that consisted of a different table for every employee. Would defeat the whole point of using SQL.
Event table could look like:
Punchin, 1, 2018/01/01 00:00
That would tell you Tom punched In at 2018/01/01 00:00. This is a very simple example, and you prob wouldn’t wanna structure an event table that way but it should get you on the right track.
This is nothing to do with MySQL but to do with your design which is flawed. You should have one table for all your employees. This contains information unique to the employees such as firstname, lastname and email address.
|ID | "John" | "Smith" | "john.smith#gmail.com" |
|1 | "James" | "Smith" | "james.smith#gmail.com" |
|2 | "jane" | "Jones" | "jane.jones.smith#yahoo.com" |
|3 | "Joanne" | "DiMaggio" | "jdimaggio#outlook.com" |
Note the ID column. Typicially this would be an integer with AUTO_INCREMENT set and you would make it the Primary Key. Then you get a new unique number every time you add a new user.
Now you have separate tables for every piece of RELATED data. E.g. the city they live in or their login time (which I'm guessing you want from the table name).
If it's a one to many relationship (i.e. each user has many login times), you create a single extra table which REFERENCES your first table. This is a DEPENDENT table. Like so:
| UserId | LoginTime |
| 1 | "10:00:04 13-09-2018" |
| 2 | "11:00:00 13-09-2018" |
| 3 | "11:29:07 14-09-2018" |
| 1 | "09:00:00 15-09-2018" |
| 2 | "10:00:00 15-09-2018" |
Now when you query your database you do a JOIN on the UserId field to connect the two tables. If it were only their LAST login time, then you could put it in the user table because it would be a single piece of data. But because they will have many login times, then login times needs to be its own table.
(N.b. I haven't put an ID column on this table but it's a good idea.)
If it's data that ISN'T unique to the each user, i.e. it's a MANY to MANY relationship, such as the city they live in, then you need two tables. One contains the cities and the other is an INTERMEDIARY table that joins the two. So as follows:
(city table)
| ID | City |
| 1 | "London" |
| 2 | "Paris" |
| 3 | "New York" |
(city-user table)
| UserID | CityID |
| 1 | 1 |
| 2 | 1 |
| 3 | 3 |
Then you would do two JOINS to connect all three tables and get which city each employee lived in. Again, I haven't added an ID field and PRIMARY KEY to the intermediary table because it isn't strictly necessary (you could create a unique composite key which is a different discussion) but it would be a good idea.
That's the basic thing you need to know. Always divide your data up by function. Do NOT divide it up by the data itself (i.e. table per user). The thing you want to look up right now is called "Database Normalization". Stick that into a search engine and read a good overview. It wont take long and will help you enormously.

Is it worth normalizing?

I am studying about databases and I have encountered this question.If I have for example the table product_supply which containts Invoice_Id(pk),Product_Id(pk),Date_Of_Supply,Quantity and Value_Of_Product.
| Invoice_ID | Product_ID | Date_Of_Supply | Quantity | Value_Of_Product |
-------------------------------------------------------------------------
| AA111111111| 5001 | 08-07-2013 | 50 | 200$ |
| AA111111111| 5002 | 08-07-2013 | 20 | 300$ |
| BB222222222| 5003 | 10-09-2013 | 70 | 50$ |
| CC333333333| 5004 | 15-10-2013 | 100 | 40$ |
| CC333333333| 5005 | 15-10-2013 | 70 | 25$ |
| CC333333333| 5006 | 15-10-2013 | 100 | 30$ |
As we Can see The table is already in the 1NF form.My question here is.In terms of normalization if it is wise to normalize this table to a 2NF form and have another table for example supply_date with Invoice_ID(pk) and Date_Of_Supply or if having the upper table is ok?
| Invoice_ID | Date_Of_Supply |
-------------------------------
|AA111111111 | 08-07-2013 |
|BB222222222 | 10-09-2013 |
|CC333333333 | 15-10-2013 |
It's definitely worth normalizing. If you need to modify a supply date, with 1NF, you need to update several records; with 2NF, you only need to update one record. Also, note the redundancy of data in 1NF, where the supply date is stored multiple times for each invoice id. Not only does it waste space, it makes it harder to process a query like "list all invoices that were supplied between dates X and Y".
EDIT
As Robert Harvey points out in his comments (which it took me a while to understand because I was being thick for some reason), if you already have a table that has a single row for each Invoice_ID (say, an "invoice table"), then you should probably add a column for Date_Of_Supply to that table rather than create a new table.
Changing the table to second normal form involves removing redundancies in the first normal form table. The first question is to determine whether there are even any redundancies.
If a redundancy exists, then we should be able to create a second table which does NOT involve the primary key (Invoice_ID) of the first one. Based on the non PK columns in the first table (namely Product_ID, Date_Of_Supply, Quantity, and Value_Of_Product), it is not clear that any of these are dependent on each other.
As a general rule of thumb, if you have a table where all non PK columns are dependent solely on the PK column of that table, it is already in 2NF.

MySql Prevent/track duplicate field across multiple fields

I'm looking for an easy way to check across multiple part tables to determine if a given part number is already present before adding it to a given table.
The current best idea I have come up with is a secondary table that simply lists every PN from all tables in a single column with a unique key; however I was wondering if there is a way to do it without creating a new table and index?
For the visual learner types, I have forty-some tables that more or less follow this pattern:
Table 1
| id | PN | Other Columns |
----------------------------------------------
| 1 | SomePn | ... ... ... ... |
...
Table 2
| id | PN | Still Other Columns |
--------------------------------------------------
| 1 | OtherPn | ... ... ... ... ... |
...
and about forty more as above, with up to 50 columns and up to 8 million records per table.
The goal is, whether through software (Java) or MySql rejecting the records, to prevent duplicate part numbers from creeping in across multiple tables. Is a master PN table the only possible or reasonable solution?
I know that the data structure is not the best design, and a rework is in progress, but I would like to know some suggested best practices as well as suggested solutions for this problem.
Adding a table is your best option.
Table 1:
| t1_id | PN | Other Columns |
----------------------------------------------
| 1 | pn_id | ... ... ... ... |
...
Table 2:
| t2_id | PN | Other Columns |
----------------------------------------------
| 1 | pn_id | ... ... ... ... |
...
Table 3:
| pn_id | PN |
------------------
| 1 | ## |
...
Although this may not be the easiest to implement solution in your case, it is the best overall solution, as you will have no scaling problems now or in the future. If you instead opted for a solution which checked all the tables for duplicate part numbers on update/creation, this would take longer and longer as your tables got bigger.
If you could guarantee that they would never get bigger or you would never add part numbers, you could probably get away with just writing a script to check for duplicates once and not worry about another table at all. But, in the long run, you'll want to add another table just to keep track of the part numbers.

How do I relate one table to many different tables?

I have a list of tables i.e. student, teacher, staff, dept. and so on and each of these tables have comments specific to them. Now one record in a table can have one or many comments that shows it's a one to many relation from any table to comments table. I don't know what the best way is to relate comments table to each of these. If I put foreign key from comments table to each of these tables, it will be like 40-50 fields depending on no. of tables. Secondly if I add foreign key from each of these tables to remarks table, it will be like repeating whole row just for the second remarks foreign key? Similarly if I use just one field in each table as comments, I will be actually storing rows in just one text field. Any suggestions on how to achieve efficient solution?
Lets assume that your tables (student, teacher, staff, dept) all have a int primary key named Id.
For your comments table you could create a table.
Id int
CommentType enum (student, teacher, staff, dept)
LinkId int
Comment
A row in Comments might look like this
1,'Student',347,'text'
As this is a many-to-many relation, you migth might want to have a look at using an associative table.
Using your example, it might look something like this:
Your tables that can have comments:
+----------+------------+
| student | student_id |
+----------+------------+
| Steve | 12 |
| Larry | 57 |
| Sunshine | 88 |
+----------+------------+
+--------+---------+
| dept | dept_id |
+--------+---------+
| Math | 2 |
| P.E. | 5 |
| Drama | 12 |
+--------+---------+
Then you need to keep track of the actual comments:
+-----------------------+------------+
| comment | comment_id |
+-----------------------+------------+
| I love Math! | 3 |
| Larry is my hero... | 5 |
| Sunshine <3 Me! | 6 |
+-----------------------+------------+
Now, you need an association between these tables, this is where your associative table comes into play. You now associate what student or dept has what comments, like this:
+------------+------------+
| student_id | comment_id |
+------------+------------+
| 57 | 5 |
| 57 | 6 |
+------------+------------+
+---------+------------+
| dept_id | comment_id |
+---------+------------+
| 2 | 3 |
+---------+------------+
This is both effective and elegant. Give it a shot!
(And to save you another question perhaps)
You could of course use just one association table if you are concerned about having so many association tables, but I would advice against it since it is not as neat and removes some possibilities for referential integrity checks that you can have with the first solution:
+-----------+------------+---------+
| entity_id | comment_id | entity |
+-----------+------------+---------+
| 57 | 5 | student |
| 57 | 6 | student |
| 2 | 3 | dept |
+-----------+------------+---------+
(Which in turn should prompt you to add a lookup table for those entities... but let's not go there)
You could use intermediate "many-to-many" tables. Each base table (student, professor, etc.) would have an alter ego storing one foreign key to the base table (e.g. student_id) and one foreign key to the commments table. You practically double your number of tables but you don't need to modify existing tables and you get full flexibility.
If you want to keep the foreign-key constraint, you need to have a table that handles the mapping for each and every table that will have comment-childs.
Meaning, Comment will have a primary key, with a foreign key constraint to each and every table that handles the mapping.
then, in the mapping-table, you have comment_id and ????_id with a foreign key constraint to the approriate table.
Your comments table could look as follows:
CommentID (int) - Primary Key
TableName (varchar(250)) - Table the comment is related to
RecordID (int) - the ID of the record in the table referred to
Comment (text) - the actual comment
You could of course add optional fields like a timestamp, which would let you select comments in the order they were entered.
Now you can use this table to store comments for any table, and you can select them by filtering on table name and record ID.
is a student or teacher or staff not just a type of person..
so you have a person and a person can have many comments? so you have a personscomments table with a relation to that person and why have a remarks table..is a remark not just a type of comment..
its hard to see without a more in-depth schema
My 50 cents: Zoredache solution is definitely good, but I discourage usage of enums; they are not very smart in mysql: if you specify an unknown value, the error is represented with an empty string - even if some default is specified. Also, it's crazily long to ALTER if you want to modify or add a new type. unsigned tinyint should be enough for most of your needs ...