Relationship with two table - mysql

I'm new to PHP, and I am working on a project for a friend of mine. He needs a system where members can register and upload images.
I have done all of that so far but my main problem is members can only upload a single image to the database seen where the image row is in the table as the registration information.
For example, if you click a single user you'll be able to see all the images which he/she uploaded to the site.
How do I create a table for a user's images and have it interact with the user's information table?

You need to add a new table into the system, which will hold multiple rows for same member_id (1 to many relationship).
For example:
CREATE TABLE `member_images` (
`image_id` BIGINT(20) UNSIGNED NOT NULL auto_increment,
`member_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
`image_path` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY(`image_id`),
KEY (`member_id`)
);
Here PK (primary key) is on a column different from member_id, so this table can hold multiple entries for the same member.

Related

Using two similar tables or flags for many-to-many relationship

I recently came across a project where I want to add some apps into a database. Every app has additional information that comes in a 1:1, 1:n or n:m relationship. Though I know how to store such relationships, I had some trouble with the developer(s) / publisher(s) for each app.
The situation:
several thousand apps
each app has its own id
several thousand companies
each company (developer/publisher) has its own id
each app can have 0, 1 or multiple developers
each app can have 0, 1 or multiple publishers
each developer can have 1 or multiple apps
each publisher can have 1 or multiple apps
It's pretty obvious that this is a many-to-many relationship and thus requires a junction table. Unfortunately, there are at least two viable options.
company
CREATE TABLE `company` (
`id` smallint(5) UNSIGNED NOT NULL,
`name` varchar(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(I merged developers and publishers in this table, because a developer can also be a publisher and vice versa. I think this is better than having redundancy in two separate tables, isn't it?)
Option 1:
The first option would be to create two separate tables.
app_developer
CREATE TABLE `app_developer` (
`id` mediumint(8) UNSIGNED NOT NULL,
`app_id` mediumint(8) UNSIGNED NOT NULL,
`company_id` mediumint(8) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
app_publisher
CREATE TABLE `app_publisher` (
`id` mediumint(8) UNSIGNED NOT NULL,
`app_id` mediumint(8) UNSIGNED NOT NULL,
`company_id` mediumint(8) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Option 2:
The second option would be to create a single table and add flags (0/1) for each app/company combination.
CREATE TABLE `app_company_rel` (
`id` mediumint(8) UNSIGNED NOT NULL,
`app_id` mediumint(8) UNSIGNED NOT NULL,
`company_id` mediumint(8) UNSIGNED NOT NULL,
`developer` tinyint(1) UNSIGNED NOT NULL,
`publisher` tinyint(1) UNSIGNED NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
I don't know if there will be the requirement to search all apps from a specific developer/publisher in the future or if it's just an additional information without further purpose.
Which option would be better (in terms of consistency, redundancy, performance) or is there no considerable difference?
Your first option will be very much efficient. Storing in two different table is actually good. Create two tables and use app_id as foreign key. Storing in two different table makes data very clear and data retrieval will also be very easy and faster. Any doubt let me know, will explain you clearly
Option 3: Like #2, but with an ENUM or SET for dev and pub.
I would consider either Option 1 or Option 3. But I would not include an id for a simple many-to-many mapping table; it slows things down.
More discussion and tips on how to write an optimal many-to-many table.
Your second option is headed the right way. But this establishes not only the relationship between a company and a project but also the type of relationship -- developer or publisher.
create table ProjCompany(
ProjID int not null references Projects( ID ),
CompanyID int not null references Company( ID ),
TypeID char( 1 ) not null references Types( ID ), -- 'D' or 'P'
constraint OK_ProjCompany primary key( ProjID, CompanyID, TypeID )
);
A project can have each company listed as a developer only once but the same company could also show up as a publisher. A company could be a developer and/or publisher for any number of projects.
If any table needed a FK reference to a particular developer of a particular project, it would reference this table with the project id, the company id and the flag for developer. If that company was not defined as a developer for that project, the reference would be rejected.
Further, I would recommend a view that would show each project and their developers and a view that would show each project and their publishers. This would come in handy for portions of code that would be working only with developers or only with publishers.

MySQL table linking 1:n

So first up I'm not sure if this is a double post or not because I don't know how the exact approach or feature is called and if it even exist.
I know that MySQL has a feature called joins
My plan is to link two MySQL tables in relation 1:n one is t_user the other one t_event.
t_user:
CREATE TABLE t_user (
uId INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(25) NOT NULL,
...
)
t_event:
CREATE TABLE t_event (
eId INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40) NOT NULL,
date DATETIME NOT NULL,
members ???,
...
)
I want the users to "subscribe" to the events and get stored in the members column as a list (?). This would be no problem if only one user would subscribe to one event. But I have no idea how to setup the t_event table to store more than one user and how to query for all the events a user has "subscribed" for.
This is usually done via third table:
CREATE TABLE t_eventsusers (
eId INT(6),
uId INT(6)
)

When to put payments in their own SQL table?

I have a system where users posts data and they can upgrade their post by optionioally paying to upgrade. This is the information I want to store from stripe on their payment response:
CREATE TABLE IF NOT EXISTS `db`.`pay` (
`payments_id` int(11) NOT NULL AUTO_INCREMENT
payment, unique index',
`stripe_id`
`card_id`
`brand`
`amount`
`created`
`currency`
`paid`
`refunded`
`exp_month`
`exp_year`
`last4`
`country`
`fingerprint`
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='payments';
Should this be in the same table as the one containing the main post data, or should it be a separate and linked table. What logic is used to make this decision?
On one hand it seems nice to separate it but then you also have the overhead of linking the tables. Only one payment will ever be associated with one post.
Card data should be in a different table with a userId that links to your user table.
With limited knowledge of what you're trying to achieve I would say you need at least 3 tables.
User Table
Post Table with userId linking back to user table
Payment Card Table with userId linking back to user table

Best way with relation tables

I have a question about tables and relations tables ...
Actually, I have these 3 tables
CREATE TABLE USER (
ID int(11) NOT NULL AUTO_INCREMENT,
NAME varchar(14) DEFAULT NULL
);
CREATE TABLE COUNTRY (
ID int(11) NOT NULL AUTO_INCREMENT,
COUNTRY_NAME varchar(14) DEFAULT NULL
);
CREATE TABLE USER_COUNTRY_REL (
ID int(11) NOT NULL AUTO_INCREMENT,
ID_USER int(11) NOT NULL,
ID_COUNTRY int(11) NOT NULL,
);
Ok, so now, 1 user can have one or more country, so, several entries in the table USER_COUNTRY_REL for ONE user.
But, my table USER contains almost 130.000 entries ...
Even for 1 country by user, it's almost 10Mo for the USER_COUNTRY_REL table.
And I have several related tables in this style ...
My question is, is it the fastest, better way to do?
This would not be better to put directly in the USER table, COUNTRY field that contains the different ID (like this: "2, 6, ...")?
Thanks guys ;)
The way you have it is the most optimal as far as time constraints go. Sure, it takes up more space, but that's part of space-time tradeoff - If you want to be faster, you use more space; if you want to use less space, it will run slower (on average).
Also, think of the future. Right now, you're probably selecting the countries for each user, but just wait. Thanks to the magic of scope creep, your application will one day need to select all the users in a given country, at which point scanning each user's "COUNTRY" field to find matches will be incredibly slow, as opposed to just going backwards through the USER_COUNTRY_REL table like you could do now.
In general, for a 1-to-1 or 1-to-many correlation, you can link by foreign key. For a many-to-many correlation, you want to have a relation table in between the two. This scenario is a many-to-many relationship, as each user has multiple countries, and each country has multiple users.
Why not try like this: Create table country first
CREATE TABLE COUNTRY (
CID int(11) NOT NULL AUTO_INCREMENT,
COUNTRY_NAME varchar(14) DEFAULT NULL
);
Then the table user:
CREATE TABLE USER (
ID int(11) NOT NULL AUTO_INCREMENT,
NAME varchar(14) DEFAULT NULL,
CID Foreign Key References CID inCountry
);
just Create a Foreign Key relation between them.
If you try to put this as explicit relation , there will lot of redundancy data.
This is the better approach. You can also make that Foreign Key as index . So that the databse retrieval becomes fast during search operations.
hope this helps..
Note : Not sure about the exact syntax of the foreign key

Database Edit with Approval - mysql

I currently have a database which many users can access and make changes to. The is also a log database that stores all changes to tables within the database using triggers.
I would like to add the ability to approve edits before they are changed in the database.
What would be the best way to go about this?
We have something similar on one of our sites, we've added a bunch of tables:
users sites ... etc
Then we have a bunch of shadow tables:
users-shadow sites-shadow ... etc
The shadow tables have identical structures to the real tables except for an added line for the user who made the change. So first we use this query when a change is submitted by a user who needs to have his/her database actions approved:
REPLACE INTO users-shadow (user_mod,id,username,password,salt...) VALUES (16,50,'bob','stuff','salt'...);
Obviously, make sure this isn't open to injection, use prepared statements etc.
When approved, a row in the shadow table is simply removed from the shadow table, the user_mod value dropped and changes (non-null values) inserted into the real table (or updated if an id is specified, using REPLACE syntax). We do this logic in perl so sadly don't have any SQL on hand for it.
Remember that SQL REPLACE does a DELETE and an INSERT rather than an UPDATE. You will need to amend any triggers to allow for this behaviour.
Note: The reason we didn't use an 'approve' flag was that we needed the ability to amend existing records, of course we couldn't have multiple records with the same primary key.
well i have made this system once and here is my solution for DB structure and over all algorithm:
there should be a sub system of admin panel which different users can manage their products but every change should be approved by administrator before going affecting the main Product table. there is three main table:
1.Product : store products that have final approved and are used in entire system
2.Changes_versions : a table with One To Many Relation with Product Table that indicates each change version is committed by who , when ,and is approved/rejected by admin or still is in Pending state .table structure is as following :
CREATE TABLE changes_versions(
xid int(11) unsigned NOT NULL AUTO_INCREMENT,
xcreated_date datetime DEFAULT NULL,
xupdated_date timestamp NULL DEFAULT NULL,
xversion int(11) DEFAULT NULL,
xobject_id int(11) DEFAULT NULL,
xobject_type varchar(255) DEFAULT NULL,
xstate enum('PENDING','ACCEPTED','REJECTED') DEFAULT 'PENDING',
PRIMARY KEY (xid)
) ENGINE=InnoDB AUTO_INCREMENT=165 DEFAULT CHARSET=utf8
3.Changes : a table that have One To Many relation with Changes_versions table that keep every column change record of the main Table (here i mean product table) and by approving a change_version record by admin its related changes records will be placed in main table column. table structure is as following :
CREATE TABLE changes(
xid int(11) unsigned NOT NULL AUTO_INCREMENT,
xcreated_date datetime DEFAULT NULL,
xcreated_by varchar(255) DEFAULT NULL,
xupdated_date timestamp NULL DEFAULT NULL,
xupdated_by varchar(255) DEFAULT NULL,
xversion_id int(11) DEFAULT NULL,
xcolumn_name varchar(255) DEFAULT NULL,
xcolumn_value varchar(255) DEFAULT NULL,
xstate enum('PENDING','ACCEPTED','REJECTED') DEFAULT 'PENDING',
xadmin_review text,
PRIMARY KEY (xid)
) ENGINE=InnoDB AUTO_INCREMENT=764 DEFAULT CHARSET=utf8
with this system and table schema i handled to work with record changes, user fetch list of records ,if user have any Pending state change_version, system will pull its related changes records and place them in the right column in the fetched product row(temporary just for displaying) , so even if user has any pending state changes he/she can see its changes in his/her panel(not main system, only his/her panel).
at the end if system administrator accept a user changes_version version and its related changes records ,system should place each changes table record in the right column of product table(for example i used product table, with this system you can versioning and admin approving any table).and change version record state to approved and its changes related records to approved to. so with this structure you can save and versioning different tables and keep log of each version changes.