relationship between tables in mysql - php

I'm learning SQL. I find very few information about command line on the web. In every tutorial I've seen on the net they stay for the create/drop/select commands and then pass to phpmyadmin.
I would like to know how to do the following by command line:
- I have 3 tables, imagine: users, cars, fuel;
- Every user has a car (from cars table) and every car has a fuel (from fuel table).
I would like to create relations between them. Not only the user could only select the cars from Cars table but I could check (by join command) who has that car type and what is spending each user for the fuel of that car.
I just want to learn how to do this by command line, it's a self made exercise to be able to solve larger problems, because relationship is one of the most important things on databases and I don't know how to use it and can't find it anywhere.

If you like do work in command line you can do it by
shell> mysql --user=[user_name] --password=[your_password db_name]
this will start the mysql command line tool. It looks like this:
mysql>
now you can do some queries like this:
mysql> show databases; // to list all your dbs
mysql> use [db_name]; // to change to your db
mysql> show tables; // to list all tables of your db
see the manual: http://dev.mysql.com/doc/refman/5.6/en/mysql.html
You can do what you want in command line but it is much more comfortable to use a gui tool like sqlyog, heidisql or the webbased phpmyadmin tool. You can see and edit your data/databases/tables here and you are able to send the same queries via your favourite gui tool.
Using constraints
If you ask for creating relations it sounds like you want to create constrains.
You dont really need constrains for a database schema. It is possible to build what you want without any constraint. The relations itself are only in your brain.
Little example with users and cars (MYISAM tables)
table user
- id_user (int)
- name (varchar)
table car
- id_car (int)
- name (varchar)
- fi_user (int)
Create Query:
CREATE TABLE `user` (
`id_user` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 64 ) NOT NULL
) ENGINE = MYISAM ;
CREATE TABLE `car` (
`id_car` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 64 ) NOT NULL ,
`fi_user` INT NOT NULL
) ENGINE = MYISAM ;
This is all you need. Simple put the id of your user into the fi_user field of your car and you have a relation.
INSERT INTO `user` (`id_user`,`name`) VALUES (1, 'testuser');
INSERT INTO `car` (`id_car`, `name`, `fi_user`) VALUES (1, 'testcar', 1);
Now you can do:
SELECT * FROM `car` c JOIN `user` u ON (u.id_user=c.fi_user) WHERE 1
It is possible to use constraints with INNODB but you dont have to use them.
I prefere MYISAM because it is faster. Please read this to find out what constraints are and why you may like to use it
http://dev.mysql.com/doc/refman/5.6/en/innodb-foreign-key-constraints.html

Related

MySQL single auto increment for two tables without duplication a better solution

i have two tables(innodb) in MYSQL data base both share a similar column the account_no column i want to keep both columns as integers and still keep both free from collusion when inserting data only.
there are 13 instances of this same question on stackoverflow i have read all. but in all, the recommended solutions where:
1) using GUID :this is good but am trying to keep the numbers short and easy for the users to remember.
2) using sequence :i do not fully understand how to do this but am thinking it involves making a third table that has an auto_increment and getting my values for the the two major tables from it.
3) using IDENTITY (1, 10) [1,11,21...] for the first table and the second using IDENTITY (2, 10) [2,12,22...] this works fine but in the long term might not be such a good idea.
4) using php function uniqid(,TRUE) :not going to work its not completely collision free and the columns in my case have to be integers.
5) using php function mt_rand(0,10): might work but i still have to check for collisions before inserting data.
if there is no smarter way to archive my goal i would stick with using the adjusted IDENTITY (1, 10) and (2, 10).
i know this question is a bit dumb seeing all the options i have available but the most recent answer on a similar topic was in 2012 there might have been some improvements in the MYSQL system that i do not know about yet.
also am using php language to insert the data thanks.
Basically, you are saying that you have two flavors of an entity. My first recommendation is to try to put them in a single table. There are three methods:
If most columns overlap, just put all the columns in a single table (accounts).
If one entity has more columns, put the common columns in one table and have a second table for the wider entity.
If only some columns overlap, put those in a single table and have a separate table for each subentity.
Let met assume the third situation for the moment.
You want to define something like:
create table accounts (
AccountId int auto_increment primary key,
. . . -- you can still have common columns here
);
create table subaccount_1 (
AccountId int primary key,
constraint foreign key (AccountId) references accounts(AccountId),
. . .
);
create table subaccount_2 (
AccountId int primary key,
constraint foreign key (AccountId) references accounts(AccountId),
. . .
);
Then, you want an insert trigger on each sub-account table. This trigger does the following on insert:
inserts a row into accounts
captures the new accountId
uses that for the insert into the subaccount table
You probably also want something on accounts that prevents inserts into that table, except through the subaccount tables.
A big thank you to Gordon Linoff for his answer i want to fully explain how i solved the problem using his answer to help others understand better.
original tables:
Table A (account_no, fist_name, last_name)
Table B (account_no, likes, dislikes)
problem: need account_no to auto_increment across both tables and be unique across both tables and remain a medium positive integer (see original question).
i had to make an extra Table_C to which will hold all the inserted data at first, auto_increment it and checks for collisions through the use of primary_key
CREATE TABLE Table_C (
account_no int NOT NULL AUTO_INCREMENT,
fist_name varchar(50),
last_name varchar(50),
likes varchar(50),
dislikes varchar(50),
which_table varchar(1),
PRIMARY KEY (account_no)
);
Then i changed MySQL INSERT statement to insert to Table_C and added an extra column which_table to say which table the data being inserted belong to and Table_C on insert of data performs auto_increment and checks collision then reinsert the data to the desired table through the use of triggers like so:
CREATE TRIGGER `sort_tables` AFTER INSERT ON `Table_C` FOR EACH ROW
BEGIN
IF new.which_table = 'A' THEN
INSERT INTO Table_A
VALUES (new.acc_no, new.first_name, new.last_name);
ELSEIF new.which_table = 'B' THEN
INSERT INTO Table_B
VALUES (new.acc_no, new.likes, new.dislikes);
END IF;
END

PhpMyAdmin SQL code not showing up when creating new database and table

I'm using WampServer with phpmyadmin, but have also tried Xamp and same results.
I have 6 entries in the table called employees:
I have a table called employee with entries:
empId, lastName, firstName, department, position, and salary.
empId is primary key w/ auto increment. I'm following a tutorial online where they are using a mac computer, I'm on windows, in case that has something to do with the issue.
When I look at the SQL this produces it shows this:
SELECT * FROM `employee` WHERE 1
I don't see any CreateTable or other SQL.
Can anyone shed some light as to what is going on here?
Thank you.
UPDATE:
So if I go to > Export to SQL:
And this is what I get:
CREATE TABLE IF NOT EXISTS employee (
empId int(11) NOT NULL,
lastName varchar(40) NOT NULL,
firstName varchar(20) NOT NULL,
department int(2) NOT NULL,
position varchar(20) NOT NULL,
salary int(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
ALTER TABLE employee
ADD PRIMARY KEY (empI);
Which looks like the correct SQL.
So at least I know it is creating the correct SQL even though its not showing on the phpmyadmin web gui page.
A CREATE TABLE statement is just a command to create a table. You can also create a table using the GUI of PHPMyAdmin, in which case it performs the necessary actions for you.
But those are just commands, blue-prints if you like. In the database itself the 'Create table' statement doesn't exist. The database contains an actual table which was created using such a statement. When you export the database (like you did) or ask for the create table statement, it just reverse-engineers the actual table structure into a statement, like drawing a blue-print based on an actual object you have.
PHPMyAdmin will often show the statement that it generated to build -for instance- a table, but in some cases you may not see it. It might be that the guy of the tutorial has a slightly different version of PHPMyAdmin, or he activated a feature that shows the statement.

Database schema for Books, Authors, Publishers and Users with bookshelves

I am unable to figure out an efficient way to establish relationships between tables. I want to have a database of books, authors, publishers and the users that sign-up and have their bookshelves (Read, Currently Reading, Want to Read (or Plan to Read)). I want the users to be able to select which books they've read, want to read or are currently reading.
P.s. I am aware of PK and FK in database table relations.
Edit: maybe this is a better way of doing it:
Then I shall use "Status" = (Read, Plant to Read and Currently reading) - please tell me if this is good and efficient!
You'll need a N:M link between books and authors, since a book might have multiple authors and each author might have written more than one book. In a RDBMS that means you'll need a written_by table.
The link between books and publishers however is different. Any given book can only have one publisher (unless in your system different editions of a book are considered the same book). So all you need here is a publisher_id foreign key in books
Lastly, and most importantly you're looking at the readers / users. And their relation to books. Naturally, this is also a N:M relation. I sure hope that people read more than one book (we all know what happens if you only ever read one...) and surely a book is read by more than one person. That calls for a book_users connection table. The real question here is, how to design it. There are three basic designs.
Separate tables by type of relation. (as outlined by #just_somebody ) Advantages: You only have INSERTS and DELETES, never UPDATES. While this looks kind of neat, and somewhat helps with query optimization, most of the time it serves no actual purpose other than showing off a big database chart.
One table with a status indicator. (as outlined by #Hardcoded) Advantages: You only have one table. Disadvantages: You'll have INSERTS, UPDATES and DELETES - something RDBMS can easily handle, but which has its flaws for various reasons (more on that later) Also, a single status field implies that one reader can have only one connection to the book at any time, meaning he could only be in the plan_to_read, is_reading or has_read status at any point in time, and it assumes an order in time this happens. If that person would ever plan to read it again, or pause, then reread from the begining etc, such a simple series of status indicators can easily fail, because all of a sudden that person is_reading now, but also has_read the thing. For most applications this still is a reasonable approach, and there are usually ways to design status fields so they are mutually exclusive.
A log. You INSERT every status as a new row in a table - the same combination of book and reader will appear more than once. You INSERT the first row with plan_to_read, and a timestamp. Another one with is_reading. Then another one with has_read. Advantages: You will only ever have to INSERT rows, and you get a neat chronology of things that happened. Disadvantages: Cross table joins now have to deal with a lot more data (and be more complex) than in the simpler approaches above.
You may ask yourself, why is there the emphasis on whether you INSERT, UPDATE or DELETE in what scenario? In short, whenever you run an UPDATE or DELETE statement you are very likely to in fact lose data. At that point you need to stop in your design process and think "What is it I am losing here?" In this case, you lose the chronologic order of events. If what users are doing with their books is the center of your application, you might very well want to gather as much data as you can. Even if it doesn't matter right now, that is the type of data which might allow you to do "magic" later on. You could find out how fast somebody is reading, how many attempts they need to finish a book, etc. All that without asking the user for any extra input.
So, my final answer is actually a question:
Would it be helpful to tell someone how many books they read last year?
Edit
Since it might not be clear what a log would look like, and how it would function, here's an example of such a table:
CREATE TABLE users_reading_log (
user_id INT,
book_id INT,
status ENUM('plans_to_read', 'is_reading', 'has_read'),
ts TIMESTAMP DEFAULT NOW()
)
Now, instead of updating the "user_read" table in your designed schema whenever the status of a book changes you now INSERT that same data in the log which now fills with a chronology of information:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='plans_to_read';
When that person actually starts reading, you do another insert:
INSERT INTO users_reading_log SET
user_id=1,
book_id=1,
status='is_reading';
and so on. Now you have a database of "events" and since the timestamp column automatically fills itself, you can now tell what happened when. Please note that this system does not ensure that only one 'is_reading' for a specific user-book pair exists. Somebody might stop reading and later continue. Your joins will have to account for that.
a database table is a mathematical relation, in other words a predicate and a set of tuples ("rows") for which that predicate is true. that means each "row" in a "table" is a (true) proposition.
this may all look scary but the basic principles are really simple and worth knowing and applying rigorously: you'll better know what you're doing.
relations are simple if you start small, with the binary relation. for example, there's a binary relation > (greater than) on the set of all integers which "contains" all ordered pairs of integers x, y for which the predicate x > y holds true. note: you would not want to materialize this specific relation as a database table. :)
you want Books, Authors, Publishers and Users with their bookshelfs (Read, Currently Reading, Want to Read). what are the predicates in that? "user U has read book B", "user U is reading book B", "user U wants to read book B" would be some of them; "book B has ISBN# I, title T, author A" would be another, but some books have multiple authors. in that case, you'll do well to split it out into a separate predicate: "book B was written by author A".
CREATE TABLE book (
id INT NOT NULL PRIMARY KEY
);
CREATE TABLE author (
id INT NOT NULL PRIMARY KEY
, name TEXT NOT NULL
);
CREATE TABLE written_by (
book INT NOT NULL REFERENCES book (id)
, author INT NOT NULL REFERENCES author (id)
);
CREATE TABLE reader (
id INT NOT NULL PRIMARY KEY
);
CREATE TABLE has_read (
reader INT NOT NULL REFERENCES reader (id)
, book INT NOT NULL REFERENCES book (id)
);
CREATE TABLE is_reading (
reader INT NOT NULL REFERENCES reader (id)
, book INT NOT NULL REFERENCES book (id)
);
CREATE TABLE plans_reading (
reader INT NOT NULL REFERENCES reader (id)
, book INT NOT NULL REFERENCES book (id)
);
etc etc.
edit: C. J. Date's Introduction to Database Systems
If I was you, I'd use a schema much like the following:
TABLE user
-- Stores user's basic info.
( user_id INTEGER PRIMARY KEY
, username VARCHAR(50) NOT NULL
, password VARCHAR(50) NOT NULL
, ...
, ...
, ...
);
TABLE author
-- Stores author's basic info
( author_id INTEGER PRIMARY KEY
, author_name VARCHAR(50)
, date_of_birth DATE
, ...
, ...
, ...
);
TABLE publisher
-- Stores publisher's basic info
( publisher_id INTEGER PRIMARY KEY
, publisher_name VARCHAR(50)
, ...
, ...
, ...
);
TABLE book
-- Stores book info
( book_id INTEGER PRIMARY KEY
, title VARCHAR(50) NOT NULL
, author_id INTEGER NOT NULL
, publisher_id INTEGER NOT NULL
, published_dt DATE
, ...
, ...
, ...
, FOREIGN KEY (author_id) REFERENCES author(author_id)
, FOREIGN KEY (publisher_id) REFERENCES publisher(publisher_id)
);
TABLE common_lookup
-- This column stores common values that are used in various select lists.
-- The first three values are going to be
-- a - Read
-- b - Currently reading
-- c - Want to read
( element_id INTEGER PRIMARY KEY
, element_value VARCHAR(2000) NOT NULL
);
TABLE user_books
-- This table contains which user has read / is reading / want to read which book
-- There is a many-to-many relationship between users and books.
-- One user may read many books and one single book can be read by many users.
-- Hence we use this table to maintain that information.
( user_id INTEGER NOT NULL
, book_id INTEGER NOT NULL
, status_id INTEGER NOT NULL
, ...
, ...
, ...
, FOREIGN KEY (user_id) REFERENCES user(user_id)
, FOREIGN KEY (book_id) REFERENCES book(book_id)
, FOREIGN KEY (status_id) REFERENCES common_lookup(element_id)
);
TABLE audit_entry_log
-- This is an audit entry log table where you can track changes and log them here.
( audit_entry_log_id INTEGER PRIMARY KEY
, audit_entry_type VARCHAR(10) NOT NULL
-- Stores the entry type or DML event - INSERT, UPDATE or DELETE.
, table_name VARCHAR(30)
-- Stores the name of the table which got changed
, column_name VARCHAR(30)
-- Stores the name of the column which was changed
, primary_key INTEGER
-- Stores the PK column value of the row which was changed.
-- This is to uniquely identify the row which has been changed.
, ts TIMESTAMP
-- Timestamp when the change was made.
, old_number NUMBER(36, 2)
-- If the changed field was a number, the old value should be stored here.
-- If it's an INSERT event, this would be null.
, new_number NUMBER(36,2)
-- If the changed field was a number, the new value in it should be stored here.
-- If it's a DELETE statement, this would be null.
, old_text VARCHAR(2000)
-- Similar to old_number but for a text/varchar field.
, new_text VARCHAR(2000)
-- Similar to new_number but for a text/varchar field.
, old_date VARCHAR(2000)
-- Similar to old_date but for a date field.
, new_date VARCHAR(2000)
-- Similar to new_number but for a date field.
, ...
, ... -- Any other data types you wish to include.
, ...
);
I would then create triggers on a few tables that would track changes and enter data in the audit_entry_log table.
First of all create 4 tables for books, authors, publishers & the users. than
create a table books_authers which has relationship with table books and table authers.
create a table books_publishers which has relationship with table books and table publishers.
create a table books_user which has relationship with table books and table users. also in this table use a flag to show the book id which user Read, Currently Reading, Want to Read (or Plan to Read).
This is just markup try it
I would have a Books table, containing: title, author, publisher, isbn. A Book_Statuses table, containing an id (PK) and a status (Read, Reading, etc..). A third table for user_books, in which there would be a fk_book_id related with the Books table, and a fk_status_id which would be linked to the Book_Statuses table.
All this together gives you an easily accessible data structure.
This is assuming I understand your question. If you want to have tables for authors, publishers and books. I'd need clarification on your needs.
Your answer is the best way to do this. For example, suppose that you have books and categories tables and a book can suit more than one category. best way to keep this data creating a third table to keep book-category relations. otherwise you have to create columns for every category.
ID name comedy adventure etc
5 BookName yes no no
like this. this is the baddest thing to do. believe me. your solution is best way to do it.
and don't aware of PK & FK in Database Table Relations. if you use them good, it will be faster and safer than doing their works manually.

Database Relationship or friend table design for a social networking site

Hello Im in the midst of creating a social networking site and I would like to know how I would go about creating the relationships between users. Many sites say that I should create a relationship/friend table, but Im looking into the future and believe that this would be ineffective. This idea could be as popular as facebook and I want to be ready for that many users. Facebook has 400 million users so a friends table would be at least 150 times that. Doing a query for ones friends would be very slow I would think. So would the solution be a seperate table for each user containing their friends ID's. or an associated CSV file containing the ID's. Any help would be greatly appreciated to the design of my site. Thanks
Build the schema you need today, not the one you think you'll need 5 years from now.
Do you think facebook designed their schema to support 400 million users on day one? Of course not. Building for that kind of scale is complicated, expensive, and honestly, if you try it now, you'll probably get it wrong and have to redo it later anyway.
And let's be honest: you have a better chance of winning the lottery than hitting 400 million users any time soon. Even if you do, your project will have hundreds of engineers by then -- plenty of bandwidth for redesigning your schema.
Now's the time to build simple.
Edit to add some solid examples:
Youtube:
They went through a common evolution:
single server, went to a single master
with multiple read slaves, then
partitioned the database, and then
settled on a sharding approach.
Keep it simple! Simplicity allows you
to rearchitect more quickly so you can
respond to problems. It's true that
nobody really knows what simplicity
is, but if you aren't afraid to make
changes then that's a good sign
simplicity is happening.
Livejournal also grew from a single database on a single server to multiple sharded replicated databases
I'm sure you could find a dozen more examples on the highscalability blog
While you think of eventually supporting millions of users, you're only ever seeing a particular persons friends list - that limits the actual amount of data substantially...
In order to maintain normalized friendship relationships in the database, you'd need two tables:
USERS
user_id (primary key)
username
FRIENDS
user_id (primary key, foreign key to USERS(user_id))
friend_id (primary key, foreign key to USERS(user_id))
This will stop duplicates (IE: 1, 2) from happening, but won't stop reversals because (2, 1) is valid. You'd need a trigger to enforce that there's only one instance of the relationship...
In your code, when inserting relationships into table, follow a convention.
issueSQLQuery("INSERT INTO relationships (friend1, friend2)
VALUES (?, ?)", min(friend_1_ID, friend_2_ID), max(friend_1_ID, friend_2_ID))
Do similarly for retrievals, as well. Of course, this could be done in a stored procedure.
Both of the alternatives you've suggested would no doubt result in grief - imagine 400 million tables, or managing 400 million files.
Definitely best to maintain a properly indexed relationships table.
If you expect the levels of success attained by Facebook (I like your confidence), you will soon realize what they realized. Relational databases begin to fall short and you'll want to look into NoSQL solutions.
That being said, why pre-optimize for 400 millions users? Build a system that will work now for, say, 500, 000 users. If you need to redesign after that, then you must be very successful and will have the resources to do so.
something like this should do you initially: http://pastie.org/1127206
drop table if exists user_friends;
drop table if exists users;
create table users
(
user_id int unsigned not null auto_increment primary key,
username varchar(32) unique not null,
created_date datetime not null
)
engine=innodb;
delimiter #
create trigger users_before_ins_trig before insert on users
for each row
begin
set new.created_date = now();
end#
delimiter ;
create table user_friends
(
user_id int unsigned not null,
friend_user_id int unsigned not null,
created_date datetime not null,
primary key (user_id, friend_user_id), -- note clustered composite PK
foreign key (user_id) references users(user_id),
foreign key (friend_user_id) references users(user_id)
)
engine=innodb;
delimiter #
create trigger user_friends_before_ins_trig before insert on user_friends
for each row
begin
set new.created_date = now();
end#
delimiter ;
drop procedure if exists insert_user;
delimiter #
create procedure insert_user
(
in p_username varchar(32)
)
proc_main:begin
insert into users (username) values (p_username);
end proc_main #
delimiter ;
drop procedure if exists insert_user_friend;
delimiter #
create procedure insert_user_friend
(
in p_user_id int unsigned,
in p_friend_user_id int unsigned
)
proc_main:begin
if p_user_id = p_friend_user_id then
leave proc_main;
end if;
insert into user_friends (user_id, friend_user_id) values (p_user_id, p_friend_user_id);
end proc_main #
delimiter ;
drop procedure if exists list_user_friends;
delimiter #
create procedure list_user_friends
(
in p_user_id int unsigned
)
proc_main:begin
select
u.*
from
user_friends uf
inner join users u on uf.friend_user_id = u.user_id
where
uf.user_id = p_user_id
order by
u.username;
end proc_main #
delimiter ;
call insert_user('f00');
call insert_user('bar');
call insert_user('bish');
call insert_user('bash');
call insert_user('bosh');
select * from users;
call insert_user_friend(1,2);
call insert_user_friend(1,3);
call insert_user_friend(1,4);
call insert_user_friend(1,1); -- oops
call insert_user_friend(2,1);
call insert_user_friend(2,5);
select * from user_friends;
call list_user_friends(1);
call list_user_friends(2);
-- call these stored procs from your php !!
You could accomplish this using a table to represent the "Relationship" that one user has with another user. This is essentially a JOIN table between two different rows in the same table. An example join table might include the following columns:
USER_1_ID
USER_2_ID
To get a list of friends write a query that performs an INNER JOIN from the USER in question to the RELATIONSHIP table back to a second instance on the USER table.

MYSQL - one column per piece of data or combine into one column

I'm creating a blog, and am storing user permissions (to post/edit/delete blog posts) in a mysql table.
Should I create one column per permission, or combine all percussions into a string in one column such as 101 would mean that a user could post and delete but not edit.
The reason I ask is that I am worried about having too many column in my table.
First of all, I would rule out combining all permissions into a single field. It seems economical at first, but it can turn into a bit of a problem if you will ever need to expand or modify your permissions structure.
Creating a column for each permission in the user table is a good design for a simple system, but may limit your future expandability.
I recommend implementing a many-to-many relationship between users and permissions. This allows you to add as many types of permissions you want without changing the schema. It is very easy to query with a simple join, and is portable to other databases.
You accomplish this by creating two new tables. Assuming the following schema:
CREATE TABLE `users` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`username` VARCHAR(100),
-- other user fields --
);
We can add the m2m permissions schema like this:
CREATE TABLE `permissions` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL UNIQUE,
);
CREATE TABLE `users_permissions` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY_KEY,
`user_id` INT NOT NULL,
`permission_id` INT NOT NULL
);
You might then add some sample users and permissions:
INSERT INTO `users` (DEFAULT, 'joe');
INSERT INTO `users` (DEFAULT, 'beth');
INSERT INTO `users` (DEFAULT, 'frank');
INSERT INTO `permissions` (DEFAULT, 'Administrator');
INSERT INTO `permissions` (DEFAULT, 'Write Blog');
INSERT INTO `permissions` (DEFAULT, 'Edit Blog');
INSERT INTO `permissions` (DEFAULT, 'Delete Blog');
And finally you can associate users with permissions like so:
-- joe gets all permissions
INSERT INTO `permissions` (DEFAULT, 1, 1);
INSERT INTO `permissions` (DEFAULT, 1, 2);
INSERT INTO `permissions` (DEFAULT, 1, 3);
INSERT INTO `permissions` (DEFAULT, 1, 4);
-- beth can write and edit
INSERT INTO `permissions` (DEFAULT, 2, 2);
INSERT INTO `permissions` (DEFAULT, 2, 3);
-- frank can only write
INSERT INTO `permissions` (DEFAULT, 3, 2);
For a smaller blog, you may not need a flexible schema like this, but it is a proven design. If you like, you can also take this one step further and create a role system. This works by giving each user a role (one-to-many), and each role has a number of permissions (many-to-many). This way permissions don't need to be set on a per-user basis, and you can simply assign them a role like "Administrator", or "Editor" or "Contributor", along with the associated permissions for that role.
My choice would be separate columns. Makes it easier to query later on if you are looking for specific permissions.
You might want to check out some standard designs on permissions, no need to invent the wheel for the 4th time :)
Consider mysql's (nonstandard) SET type. More experienced coders may favor a bit field (which is really what's underneath mysql's SET type).
Don't use a string because:
A string is a very inefficient way to store bit values -- you're using a byte per flag, where you only need a single bit
Querying against that field would require heinous string manipulations, and would never be efficient
I'd say it would be fine to put a Post, Edit and Delete Column.
But, if you take Wordpress's take on permissions, they simply serialize it into an array, and then store that array in a table of Settings (4 Columns: UserID, Settings Key, Setting Value). I think Wordpress's method only really works if you aren't going to give permissions their own table.
Another method is to do a User_ID - Permission Relationship Table. In one column put the User_ID, and in the other the permission. But, make each row a permissions. IE, if you wanted to give User ID 1 all permissions it would be:
Permissions: Add: 1, Edit: 2, Delete: 3
Table
Row 1: UserID: 1 Permission: 1
Row 2: UserID: 1 Permission: 2
Row 3: UserID: 1 Permission: 3
You could use bitwise combinations (bit fields) within one column like
const READ = 1;
const WRITE = 2;
const DELETE = 4;
...
so resulting permission would be
read-only: 1
read-write: 3
read & delete, but not write: 5
and so on...
To check the permission in a bit field, your query has to look like
SELECT * FROM table t WHERE t.permission & required_permission
with required_permission being the bitwise or of the required permission flags.
But I also would recommend to check out some resources to find out about standard designs...

Categories