Link another table based on a column value - mysql

Hi, I'm designing a item catalog using MySQL and Squalize ORM (NodeJS).
Suppose I have a product list with different attributes based on its category (attributes_id in this case).
I would like to get a product by using a JOIN statement with an appropriate attribute table. The design should be scalable as we will have more than a hundred attribute tables.
Roughly the statement will look like this:
JOIN
if ( product.attributes_id == 1 ) 'attributes_car'
elseif ( product.attributes_id == 2 ) 'attributes_food'
BUT the the number of elseif cases will grow more than a hundred later.
So the question is how to design attributes_id? Is it a good idea to make it a foreign key to the database metadata (like INFORMATION_SCHEMA) to point to another table? Should I introduce another table to manage such relationship?
One of option is a Dynamic SQL but I don't think it is a good idea because the ifelse cases should grow.
Or should I give up designing a query and just implement such logic on NodeJS side using ORM?
Thank you!

One solution would be to create an additional table that stores attribute_id and table_name.
Create table attibute_tablename(
attribute_id int(11),
table_name varchar(25),
PRIMARY KEY (attribute_id, table_name)
)
You can also add a foreign key to the product table if you want.
Then you only need an insert to this table for every new item added

Related

Nullable foreign keys - good or bad practice?

Let's assume I have 2 tables: foo and bar.
In third table I want to store different kind of data, however every row will have a reference to either foo OR bar.
Is it correct if I create 2 NULLable foreign keys - foo_id and bar_id - in the third table, or is it againts database design principles?
Basically, I thought all the time that foreign keys need to ALWAYS have a "parent", so if I try to e.g. INSERT a row with no primary key matched (or, in this case, with a foreign key set to NULL), I will get an error. Nullable FK-s are new to me, and they feel a bit off.
Also, what are the alternatives? Is it better to create separate tables storing single reference? Isn't this creating redundancy?
Linking tables?
Help.
A nullable FK is "okay". You will still get an error when you try to insert a non-existing parent key (it is just NULL that is allowed now).
The alternative is two link tables, one for foo and one for bar.
Things to consider:
Link tables allow for 1:N. If you don't want that, you can enforce it by primary key on the link table. That is not necessary for the id column solution (they are always 1:N).
You can avoid columns with mostly NULL values using link tables. In your case, though, it seems that you have NULL for exactly half the values. Probably does not qualify as "mostly". This becomes more interesting with more than two parent tables.
You may want to enforce the constraint that exactly one of your two columns is NULL. This can be done with the id column version using a check constraint. It cannot be done with link tables (unless you use triggers maybe).
it is depend on the business logic of the program. if the foreign key field must has a value , it is bad to set it null-able .
for example .
a book table has category_id field which the value is reference from bookCategory table.
each record in book table must has category . if for some reason you set it as nullable . this will cause some record in book table with category_id is null.
the problem will show up in report. the following 2 query will return different total_book
select count(*) as total_book from book;
select
count(*) as total_book
from
book
inner join bookCategory
on book.category_id = category.id
my advice is don't use null-able unless you expect value and no-value . alot of complex system that sometime have value different from one report and another , usually is cause by this.

MySQL database with user created tables with custom column numbers

I have a person table and I want users to be able to create custom many to many relations of information with them. Educations, residences, employments, languages, and so on. These might require different number of columns. E.g.
Person_languages(person_fk,language_fk)
Person_Educations(person,institution,degree,field,start,end)
I thought of something like this. (Not correct sql)
create Tables(
table_id PRIMARY_KEY,
table_name_fk FOREIGN_KEY(Table_name),
person_fk FOREIGN_KEY(Person),
table_description TEXT
)
Table holding all custom table name and descriptions
create Table_columns(
column_id PRIMARY_KEY,
table_fk FOREIGN_KEY(Tables),
column_name_fk FOREIGN_KEY(Columns),
rank_column INT,
)
Table holding the columns in each custom table and the order they are to be displayed in.
create Table_rows(
row_id PRIMARY_KEY,
table_fk FOREIGN_KEY(Tables),
row_nr INT,
)
Table holding the rows of each custom table.
create Table_cells(
cell_id PRIMARY_KEY,
table_fk FOREIGN_KEY(Tables),
row_fk FOREIGN_KEY(Table_rows),
column_fk FOREIGN_KEY(Table_columns),
cell_content_type_fk FOREIGN_KEY(Content_types),
cell_object_id INT,
)
Table holding cell info.
If any custom table starts to be used with most persons and becomes large, the idea was to maybe then extract it into a separate hard-coded many-to-many table just for that table.
Is this a stupid idea? Is there a better way to do this?
I strongly advise against such a design - you are on the road to an extremely fragmented and hard to read design.
IIUC your base problem is, that you have a common set of (universal) properties for a person, that may be extended by other (non-universal) properties.
I'd tackle this by having the universal properties in the person table and create two more tables: property_types, which translates a property name into an INT primary key and person_properties which combines person PK, propety PK and value.
If you set the PK of this table to be (person,property) you get the best possible index locality for the person, which makes requesting all properties for a person a very fast query.

How to create a "following" table?

I am designing a simple twitter site ( for study ) but with a little bit different: the users can follow other users, keywords and lists. I want to know how to create a following table to put information about following.
Is this approach ( below ) correct ?
Following Table:
id ( id of the following table )
type ( type can be 1 ( user ), 2 ( keyword ) or 3 ( list ) )
idtype ( id of the type table )
user ( user's id )
However there isn't a keyword table. So I don't know.
What is the best approach ?
It's incorrect because you can't create a foreign key from idtype to the parent table, because "parent table" changes depending on type. BTW, if user can follow multiple keywords, then you won't escape having a separate table for that (unless you want to break the 1NF by "packing" several values into the same field, which is a really bad idea).
There are couple of ways to resolve this, probably the simplest one is to use separate id fields for each of the possible parent tables, and then constrain them so only one of them can be non-NULL.
However, since InnoDB tables are clustered and secondary indexes in clustered tables are expensive, I'd rather go with something like this (tweets table not shown):
This will enable you to very efficiently answer the query: "which users follow the given user (or keyword or list)". If you need to answer: "which users (or keywords or lists) the given user follows", reverse the order of fields in the PKs shown above. If you need both, then you'd need indexes in both directions (and pay the clustering price).

mysql many to many relationship

Been reading the tutorial How to handle a Many-to-Many relationship with PHP and MySQL .
In this question I refer to the "Database schema" section which states the following rules:
This new table must be constructed to
allow the following:
* It must have a column which links back to table 'A'.
* It must have a column which links back to table 'B'.
* It must allow no more than one row to exist for any combination of rows from table 'A' and table 'B'.
* It must have a primary key.
Now it's crystal clear so far.
The only problem I'm having is with the 3rd rule ("It must allow no more than one row to exist for any combination").
I want this to be applied as well, but it doesn't seem to work this way.
On my test instance of mysql (5.XX) I'm able to add two rows which reflect the same relationship!
For example, if I make this relation (by adding a row):
A to B
It also allows me to make this relation as well:
B to A
So the question is two questions actually:
1) How do I enfore the 3rd rule which will not allow to do the above? Have only one unique relation regardless of the combination.
2) When I'll want to search for all the relations of 'A', how would the SQL query look like?
Note #1: Basically my final goal is to create a "friendship" system, and as far as I understand the solution is a many-to-many table. Suggest otherwise if possible.
Note #2: The users table is on a different database from the relations (call it friendships) table. Therefore I cannot use foreign keys.
For the first question:
Create a unique constraint on both
columns
Make sure you always sort the columns. So if your table has the
colummns a and b than make sure
that a is less than or equal to
b
For the second question:
SELECT
*
FROM
many_to_many_table
WHERE
a = A or b = A
It sounds like you want a composite primary key.
CREATE TABLE relationship (
A_id INTEGER UNSIGNED NOT NULL,
B_id INTEGER UNSIGNED NOT NULL,
PRIMARY KEY (A_id, B_id)
);
This is how you setup a table so that there can only ever be one row that defines tables A and B as related. It works because a primary key has to be unique in a table so therefore the database will allow only one row with any specific pair of values. You can create composite keys that aren't a primary key and they don't have to be unique (but you can create a unique non-primary key, composite or not), but your specification requested a primary key, so that's what I suggested.
You can, of course, add other columns to store information about this specific relationship.
Ok WoLpH was faster, I basically agree (note that you have to create a single constraint on both columns at the same time!). And just to explain why you collide with the rules you mentioned: Typically, A and B are different tables. So the typical example for n:m relations would allow entries (1,0) and (0,1) because they'd be refering to different pairs. Having table A=table B is a different situation (you use A and B as users, but in the example they're tables).

MySQL practical normalisation on large single table

I'm relatively new to PHP MySQL and have tasked myself on learning with the "hands on" approach. Luckily, I currently have a (very) large database all relating to coin data with one table to work with. It currently has the following columns (each row representing a single item [coin]):
Group
ItemNo
ListNo
TypeCode
DenomCode
PeriodCode
ActualDate
SortDate
CostPrice
SalePrice
Estimate
StockLevel
DateEntered
DateSold
Archived
ArchiveWhenSold
Highlight
KeepSold
OnLists
NotForSale
Proof
StockItem
OnWeb
Cats
Ref1
Ref2
Variety
Picture
Description
TypeName
TypeHeading
DenomName
DenomHeading
DenomValue
PeriodName
PeriodHeading
PeriodStartYear
PeriodEndYear
The groupings for new tables are relatively obvious:
Period:
PeriodCode
PeriodName
PeriodHeading
PeriodStartYear
PeriodEndYear
Denom:
DenomCode
DenomName
DenomHeading
DenomValue
Type:
TypeCode
TypeName
TypeHeading
All the rest, under a Coin table:
Group
ItemNo
ListNo
TypeCode
ActualDate
SortDate
CostPrice
SalePrice
Estimate
StockLevel
DateEntered
DateSold
Archived
ArchiveWhenSold
Highlight
KeepSold
OnLists
NotForSale
Proof
StockItem
OnWeb
Cats
Ref1
Ref2
Variety
Picture
Description
So I'm looking to normalise the table into the tables specified. I know that i'm looking at JOINs but am wondering the best way to go about it. Do I create a new table FIRST with each data group (Denom, Period, Type) and THEN insert the data using a JOIN statement? Or is there a way to create new tables "on the fly" with a JOIN statement. I've got a honking great book open here and am following along nicely the section on MySQL and also looking through this site, but haven't been able to figure out the "correct" way to do this.
The reason I ask here for some knowledgable advice is that i'm a little unsure about how to maintain the "relationships" and keys etc. i.e If I create a table called "Denom" and populate it with all the distinct items from all the current tables data and also have it create a unique primary key, how to I then insert the reference to this new primary key from the Denom table into the main Coin table (under a new item DenomID) so that they match up?
I basically need to split this table up into 4 separate tables. I've tried this using Access 2007's table analyzer wizard and it looked promising for a n00b like me, but there was so much data, it actually crashed. Repeatedly. Probably for the best, but now I need to know some best practice, and also HOW to put it into practice. Any advice/help/relevant links would be greatly appreciated.
Create the tables first, don't forget to add a foreign key field to all the child tables that contains the Primary key from the main table (also each new table must get a primary key), so that you can join the tables. If you don't have a primary key, you need to create one before doing anything else.
To put the data into the tables is a simple insert
insert tableb (field1, field2)
select field1, field2 from tablea
You will join to get the database out, so rememebr to create indexes on the new tables especially onthe foreign key field.