Multiple possible relationships on table - mysql

I have a table that contains account information for various entities in the database. Currently the table design is something like:
CREATE TABLE account (id int(11) NOT NULL auto_increment,
account_id int(11) NOT NULL,
account_type varchar(15) NOT NULL,
balance decimal(12,2) NOT NULL,
PRIMARY KEY (id))
The account_id column references (not database enforced) one of 3 tables. The account_type column tells the programmer which table to reference. I do not like this approach, because I cannot enforce the relationship and the programmers can accidentally corrupt the data. I have considered doing one of the following:
Adding a nullable foreign key for each type, or dropping the account_id column and adding a cross reference table to link the account to the entities. The account_type column would be used to tell the programmers which cross reference table to access. Are there any other options? What is the best practice for something like this?

You could try having a master identity table from which the three shared-identity tables draw their primary keys. Your account table in the question would then link to the master table. Loosely described:
MasterIdentity
Id (autoincrement)
IdentityType (string, maybe FK to a type lookup table, whatever you want)
Table1
Id (PK, FK to MasterIdentity)
other data
Table2
Id (PK, FK to MasterIdentity)
other data
Table3
Id (PK, FK to MasterIdentity)
other data
Account
Id (its own identifier as you already have)
AccountID (FK to MasterIdentity)
other data
Inserting into any of the three tables would involve inserting into MasterIdentity, grabbing the scope identity value from the insert, and inserting into the desired table directly specifying the Id. (This would all have to be atomic within a transaction, of course.) Note that the Id on the three tables are not auto-increment values, you'd provide them.
Then any table which needs to refer to those three (non-overlapping, I assume) tables would have a single table to refer to which has the identity and the type, the latter of which tells you which sub-table has the rest of that record's data.
(I'm pretty sure this is called a supertype/subtype table relationship, but I can't say for certain.)

Related

What decides what constrains to use when creating table from a physical schema

I am learning SQL and going trough some lab exercises when i got to a question that asks to create table from a physical schema. No problem there, simple enough to create a table, but i got it wrong because i didn't use the NOT NULL, NULL, and FKconstraints. So what in this schema tells me what constrains to use? Here is the correct answer according to the exercise. (the auto increment was provided in the question)
CREATE TABLE customerorder (DonutOrderID INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
CustomerID INT(11) NOT NULL,
DonutOrderTimestamp TIMESTAMP DEFAULT NOW(),
SpecialNotes VARCHAR(500) NULL,
FOREIGN KEY (CustomerID) REFERENCES Customer(CustomerID));
A customerorder without a customer makes no sense, so its customer ID column should not be nullable.
A customerorder must refer to an existing customer, so you should make the customer ID a foreign key to the customer table.
SpecialNotes are only special when they are optional in my opinion, so the should be nullable.
If the table is called customerorder, its ID should not be called DonutOrderID, as this name looks somewhat unrelated and I'd expect some additional DonutOrder table in the database. The customerorder's ID should be called id or customerorder_id or the like instead.
As a customer order seems to be a donat order in that database, the DonutOrderTimestamp should probably be obligatory (i.e. not nullable), as every order is placed at some point in time.

Relationships midst two tables?

I have table visitors and table users. Each visitor can be created by only one user and contains field visitors.userId.
So, any another user from table users can edit or delete one or more visitors.
I have created a third table events_log for logging actions like edit/delete:
Visitors_log
id | userId | visitorId | action
This table stores information about user who did actions over table visitors.
Which relationship should be between table visitors_log and rest two: users and visitors?
Now I have this Db scheme:
My opinion is: visitors_log can have one or more rows. So relations is one to many. In the same time visitors_log can contain one or more users. So, where I am wrong? Now it is one to one relation.
Is there a possibility that the user_id of a visitor could ever change ?
If the answer is yes, then you would better take the safe approach and have two foreign keys in the log, referencing the concerned visitor and the user that commited the action.
In MySQL :
CREATE TABLE visitors_log (
idVisitorLog INT AUTO_INCREMENT,
idVisitor INT NOT NULL,
idUser INT NOT NULL,
action VARCHAR(100) NOT NULL,
date_action DATETIME NOT NULL,
PRIMARY KEY (idVisitorLog),
FOREIGN KEY (visitor_log_idVisitor) REFERENCES visitors(idVisitor),
FOREIGN KEY (visitor_log_idUser) REFERENCES users(idUser)
);
PS : you probably want a date column too in the log table, I added one.
On the other hand, if the user a visitor is assigned to can never change over time, then your design can be simplified. In the log table, you could just store a foreign key to the visitors table. As the visitor stores a (fixed) user id, you do not need to duplicate that information in the log.

Primary And Foreign key mapping between view and table

I have created 2 table in 2 different databases. First database name is user which contains userDetails table, which have id as a primary key and user_name, and my second database is customer which have 1 table called as customerDetails, which have 1 id as a primary key and customer name and one view of above user table which contains id of that user table and name.
So what i want to do is, creating a foreign key of that view in customerDetails table, so that i can access user table from customer database through view. I don't know how to achieve this, as i am new to database concepts please anyone can get me out of this.
Whole scenario is as follow,
> Database Name : user
> Table Name : userDetails
> Fields : id userName
>
> Database Name : customer
> View Name : user_view
> Fields : id userName
>
> Database Name : customer
> View Name : customerDetails
> Fields : id custName
i want in last table that is in customerDetails last column as a foreign key from view. How can i achieve this?
Views are not related to foreign keys as much as getting to your data as mentioned in comments by your peers. The below uses a Junction Table to intersect users and companies, enforcing a Foreign Key constraint between databases (not a bad idea for shared info between databases).
The Junction Table is many-to-many, and hooks users and companies together.
Schema:
create schema userDB;
create table userDB.userDetails
( id int auto_increment primary key,
userName varchar(100) not null
);
create schema customerDB;
create table customerDB.customerDetails
( id int auto_increment primary key,
custName varchar(100) not null
);
create table customerDB.userCustomerJunction
( -- a many-to-many mapping
id int auto_increment primary key,
userId int not null,
custId int not null,
unique key (userId,custId), -- no dupes allowed
foreign key `ucj_2_user` (userId) references userDB.userDetails(id),
foreign key `ucj_2_cust` (custId) references customerDb.customerDetails(id)
);
Test it:
insert customerDB.customerDetails(custName) values ('Exxon Mobil'); -- id 1
insert customerDB.userCustomerJunction(userId,custId) values (1,7); -- FK Failure
-- above line generates an error 1452 as expected
insert userDB.userDetails(userName) values ('Kelly'); -- id 1
insert customerDB.userCustomerJunction(userId,custId) values (1,1); -- success, FK's satisfied
Remember that the user and company are separate entities and to interface the two would require something that ties them together. A Junction table is a fantastic place to put a column such as effectiveRights or something. It would denote what the user can do, such as insert, update, delete, view, blacklist, etc.
Creating a view between user and company is simply like any join, but in this case it would be between databases with the whichDB. in front of the table name. The view is materialized and manifested in the physical tables. So as the physical rules, the physical has the FK's in force (data integrity). And the addition of an effectiveRights column will assist you in determining what each user and company can do together: such as, yes, this user has certain rights to this company info, etc. With a rights bitmark, or separate columns for rights, all in the Junction table. For an example of Junction tables, see this Answer of mine.

Multitable constraints for a column value in sql database

I have a three tables, a project table, there may be many projects, a subjects table, where each project will have many subjects and a condition table where each subject will have a condition and a project may have many conditions.
How to restrict the condition that the subjects can have based on the conditions that the project is linked to given that the subject must be in one of the projects.
Hope that makes sense. Also, I am thinking of using sqlite but if it is not possible to do something like this with the database system does there exist one that can? Preferebly free and sql based ie mysql or postgresql.
Thanks.
edit: some examples;
project A has conditions 1, 2 and 3. All are drawn from the condition table which has conditions 1,2,3,4,5. Now subject X is part of project A so should only be allowed to assume conditions 1,2,3 NOT 4 or 5.
Is this possible?
Looks like you need something similar to this:
The key aspect of this design the the usage of identifying relationships and the resulting composite keys. This allows us to migrate PROJECT.PROJECT_ID:
not just directly to SUBJECT
but also through CONDITION and then to SUBJECT.
Both of these "paths" of migration eventually get merged into the same field (note FK1,FK2 in front of SUBJECT.PROJECT_ID), which ensures that when a subject is connected to a condition, they both must be connected to the same project.
create table Condition(
Id int not null, --PK
Description varchar(50)
)
create table ProjectCondition(
Id int not null, --PK
ProjectId int not null, -- FK to Project PK#
ConditionId int not null -- FK to Condition PK
)
create table ProjectSubject(
Id int not null, --PK
ProjectId int not null, -- FK to Project PK
SubjectId int not null -- FK to Subject PK
)
create table ProjectSubjectCondition(
Id int not null, -- PK
ProjectConditionId int not null -- FK to ProjectContion PK
)
Assumptions:
Subject has an existence separate from Project (i.e. there is a
Subject table somewhere)
Condition is the same
(Doesn't make much difference if they're wrong.)
By linking the ProjectSubjectCondition to the ProjectConditions the condition of a subject for a project must be a condition of the project.
Cheers -

Sql Query join suggestions

I was wondering when having a parent table and a child table with foreign key like:
users
id | username | password |
users_blog
id | id_user | blog_title
is it ok to use id as auto increment also on join table (users_blog) or will i have problems of query speed?
also i would like to know which fields to add as PRIMARY and which as INDEX in users_blog table?
hope question is clear, sorry for my bad english :P
I don't think you actually need the id column in the users_blog table. I would make the id_user the primary index on that table unless you have another reason for doing so (perhaps the users_blog table actually has more columns and you are just not showing it to us?).
As far as performance, having the id column in the users_blog table shouldn't affect performance by itself but your queries will never use this index since it's very unlikely that you'll ever select data based on that column. Having the id_user column as the primary index will actually be of benefit for you and will speed up your joins and selects.
What's the cardinality between the user and user_blog? If it's 1:1, why do you need an id field in the user_blog table?
is it ok to use id as auto increment also on join table (users_blog)
or will i have problems of query speed?
Whether a field is auto-increment or not has no impact on how quickly you can retrieve data that is already in the database.
also i would like to know which fields to add as PRIMARY and which as
INDEX in users_blog table?
The purpose of PRIMARY KEY (and other constraints) is to enforce the correctness of data. Indexes are "just" for performance.
So what fields will be in PRIMARY KEY depends on what you wish to express with your data model:
If a users_blog row is identified with the id alone (i.e. there is a "non-identifying" relationship between these two tables), put id alone in the PRIMARY KEY.
If it is identified by a combination of id_user and id (aka. "identifying" relationship) then you'll have these two fields together in your PK.
As of indexes, that depends on how you are going to access your data. For example, if you do many JOINs you may consider an index on id_user.
A good tutorial on index performance can be found at:
http://use-the-index-luke.com
I don't see any problem with having an auto increment id column on users_blog.
The primary key can be id_user, id. As for indexing, this heavily depends on your usage.
I doubt you will be having any database related performance issue with a blog engine though, so indexing or not doesn't make much of a difference.
You dont have to use id column in users_blog table you can join the id_user with users table. also auto increment is not a problem to performance
It is a good idea to have an identifier column that is auto increment - this guarantees a way of uniquely identifying the row (in case all other columns are the same for two rows)
id is a good name for all table keys and it's the standard
<table>_id is the standard name for foreign keys - in your case use user_id (not id_user as you have)
mysql automatically creates indexes for columns defined as primary or foreign keys - there is no need to do anything here
IMHO, table names should be singular - ie user not users
You SQL should look something like:
create table user (
id int not null auto_increment primary key,
...
);
create table user_blog (
id int not null auto_increment primary key,
id_user int not null references user,
...
);