Should mailing addresses be normalized in SQL? - php

Should mailing addresses with city, state, and zip code be normalized? I am currently concerned with US addresses only.I have shown a normalized tables along with an ERD, and a non-normalized table at the bottom of this post. Please provide rational for your answer.
Note that To Normalize or Not To Normalize is related to this topic, but is different.
Thank you
CREATE TABLE IF NOT EXISTS states (
id CHAR(2) NOT NULL ,
name VARCHAR(45) NULL DEFAULT NULL ,
PRIMARY KEY (id) ,
INDEX states_name (name ASC) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS cities (
id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
name VARCHAR(45) NOT NULL ,
states_id CHAR(2) NOT NULL ,
PRIMARY KEY (id) ,
INDEX fk_zipcodes_states1_idx (states_id ASC) ,
UNIQUE INDEX makeUnique (states_id ASC, name ASC) ,
INDEX cities_name (name ASC) ,
CONSTRAINT fk_zipcodes_states1
FOREIGN KEY (states_id )
REFERENCES states (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
PACK_KEYS = 0
ROW_FORMAT = DEFAULT;
CREATE TABLE IF NOT EXISTS zipcode_types (
id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
name VARCHAR(45) NULL DEFAULT NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB
PACK_KEYS = 0
ROW_FORMAT = DEFAULT;
CREATE TABLE IF NOT EXISTS counties (
id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
name VARCHAR(45) NOT NULL ,
PRIMARY KEY (id) ,
INDEX counties_name (name ASC) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS timezones (
id CHAR(4) NOT NULL ,
name VARCHAR(45) NOT NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB
PACK_KEYS = 0
ROW_FORMAT = DEFAULT;
CREATE TABLE IF NOT EXISTS zipcodes (
id CHAR(5) NOT NULL ,
longitude DECIMAL(9,6) NOT NULL ,
latitude DECIMAL(9,6) NOT NULL ,
zipcode_types_id INT UNSIGNED NOT NULL ,
counties_id INT UNSIGNED NOT NULL ,
timezones_id CHAR(4) NOT NULL ,
PRIMARY KEY (id) ,
INDEX fk_zipcodes_zipcode_types1_idx (zipcode_types_id ASC) ,
INDEX fk_zipcodes_counties1_idx (counties_id ASC) ,
INDEX fk_zipcodes_timezones1_idx (timezones_id ASC) ,
CONSTRAINT fk_zipcodes_zipcode_types1
FOREIGN KEY (zipcode_types_id )
REFERENCES zipcode_types (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_zipcodes_counties1
FOREIGN KEY (counties_id )
REFERENCES counties (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_zipcodes_timezones1
FOREIGN KEY (timezones_id )
REFERENCES timezones (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS cities_has_zipcodes (
cities_id INT UNSIGNED NOT NULL ,
zipcodes_id CHAR(5) NOT NULL ,
PRIMARY KEY (cities_id, zipcodes_id) ,
INDEX fk_cities_has_zipcodes_zipcodes1_idx (zipcodes_id ASC) ,
INDEX fk_cities_has_zipcodes_cities1_idx (cities_id ASC) ,
CONSTRAINT fk_cities_has_zipcodes_cities1
FOREIGN KEY (cities_id )
REFERENCES cities (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_cities_has_zipcodes_zipcodes1
FOREIGN KEY (zipcodes_id )
REFERENCES zipcodes (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS someRecord (
id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
data VARCHAR(45) NULL ,
address VARCHAR(45) NULL ,
cities_id INT UNSIGNED NOT NULL ,
zipcodes_id CHAR(5) NOT NULL ,
PRIMARY KEY (id) ,
INDEX fk_someRecord_cities1_idx (cities_id ASC) ,
INDEX fk_someRecord_zipcodes1_idx (zipcodes_id ASC) ,
CONSTRAINT fk_someRecord_cities1
FOREIGN KEY (cities_id )
REFERENCES cities (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT fk_someRecord_zipcodes1
FOREIGN KEY (zipcodes_id )
REFERENCES zipcodes (id )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Example of data in a single table
CREATE TABLE IF NOT EXISTS otherRecord (
id INT UNSIGNED NOT NULL AUTO_INCREMENT ,
data VARCHAR(45) NULL ,
address VARCHAR(45) NULL ,
city VARCHAR(45) NULL ,
state VARCHAR(45) NULL ,
zipcode VARCHAR(45) NULL ,
county VARCHAR(45) NULL ,
longitude DECIMAL(9,6) NULL ,
latitude DECIMAL(9,6) NULL ,
timezone VARCHAR(45) NULL ,
PRIMARY KEY (id) )
ENGINE = InnoDB;

Yes, if:
You will be analyzing your data with respect to their addresses, and by that I mean sorting, filtering, grouping, counting based on the various fields of an address.
If you allow free text, then you might have country names like US, USA, U.S.A., United States. This will be a pain if you want to view/count/group all American customers. Your internal users might want to drill down from continent to country to state to county to city, in which case your data needs to be normalized.
You will be doing matching against external sources. For example, you have data from a 3rd party vendor, and you need to match their Company A and your Company A. Oftentimes companies have similar names, and you need to match by (parts of) the address. For example, you need to match "Acme, Inc | California" with "Acme Incorporated | CA".
You want to truly avoid duplication. If you allow free text, then you would have a duplicate with "123-456 Main Street, Vancouver" and "Apt 123, 456 Main Street, Vancouver"
You want truly valid data. If you allow free text, then anyone can type in anything. This one is tough, as you'll need lots of reference data with available country names, state names, county names, even street names. You could start with getting some data from geonames.org .
Please note, Ireland does not use Postal Codes, so your schema needs to account for that if going global. Read Hay's Enterprise Model Patterns for some good Address models.

Addresses are not a cleanly relational entity. You should not normalize them in the traditional sense. What you may want to do is additionally store a normalized version of parts of the address (e.g. country, state, city) for your own analysis purposes, which is derived from the address provided by the user.
There are a tremendous number of exceptions in just US addresses, which are pretty well normalized compared to the rest of the world. Zip codes, by the way, correspond primarily to delivery routes by the USPS, not to specific physical locations.
As a personal example, I live in an unincorporated area which is served by a post office in a different (nearby) city, which is in a different county. My official address should, according to USPS, be written as "VC Highlands, NV 89521" and is in Storey County, NV. However the Zip code 89521 is primarily in "Reno, NV 89521" and is in Washoe County, NV. You can imagine that this causes is much trouble with just about everyone. Even the Nevada DMV refuses to accept "VC Highlands" because their database thinks 89521 is "Reno".
So even just with something "simple" in your above schema, you've got it wrong. A zip code can not only span multiple cities, but multiple counties. There are thousands more exceptions which will certainly frustrate some percentage of your users.

Related

MySQL Inline Foreign Key doesn't apply restrictions

I have two tables one is a primary table and the other one is child table/foreign key table and I don't have any row in the primary table but still child table accepts row insertion without any restriction... Why it is happening
CREATE TABLE CUSTOMERS(
ID INT NOT NULL,
NAME VARCHAR (20) NOT NULL,
AGE INT NOT NULL,
ADDRESS CHAR (25) ,
SALARY DECIMAL (18, 2),
PRIMARY KEY (ID)
);
CREATE TABLE ORDERS (
ID INT NOT NULL,
DATE DATETIME,
CUSTOMER_ID INT references CUSTOMERS(ID),
AMOUNT double,
PRIMARY KEY (ID)
);
when I insert the data into the child table wihtout inserting into primary tbl, it accepts .. but it shouldn't.. please help
CUSTOMER_ID INT references CUSTOMERS(ID)
From the MySQL CREATE TABLE documentation :
MySQL parses but ignores “inline REFERENCES specifications” (as defined in the SQL standard) where the references are defined as part of the column specification. MySQL accepts REFERENCES clauses only when specified as part of a separate FOREIGN KEY specification.
You should explictly declare the foreign key, like :
CREATE TABLE ORDERS (
ID INT NOT NULL,
DATE DATETIME,
CUSTOMER_ID INT,
AMOUNT DOUBLE,
PRIMARY KEY (ID),
FOREIGN KEY (CUSTOMER_ID) REFERENCES CUSTOMERS(ID)
);
Also, it is generally a good idea to make the referencing column not nullable, as the foreign key by default allows NULL values.
CREATE TABLE ORDERS (
ID INT NOT NULL,
DATE DATETIME,
CUSTOMER_ID INT NOT NULL,
AMOUNT DOUBLE,
PRIMARY KEY (ID),
FOREIGN KEY (CUSTOMER_ID) REFERENCES CUSTOMERS(ID)
);
Demo on DB Fiddle
You have to declare the foreign key column "not null" if you don't want to allow null values there.
CREATE TABLE ORDERS (
ID INT NOT NULL,
DATE DATETIME,
CUSTOMER_ID INT NOT NULL references CUSTOMERS(ID),
AMOUNT double,
PRIMARY KEY (ID)
);

how to get users information stored in several tables and show in his profile, is it posible with single query?

i have developed an online auction system in which users can sale or buy goods, my problem is with retrieving auctions relative information that are in two separate tables one contains information such as (auction_id,owner,title,description,base_price,..) and the other contains information about requests for each auction: (bid_id,auction_id,bidder,price,date), each user may post several auctions or not, i want to show the highest price and the bidder(some one who gives such price) for that price and number of requests additional to information stored in auction table for each auction
but when i join to table, if there is no request for auction so the result will be zero and you will see the message: there is no information to show but the user has just posted a new auction, what should i do?! should i check if there is a request for each auction and if yes then get these information?! dosent in code duplication? in this way i should connect to db twice in a single request for profile page
here is my tables and current query:
create table `auction`(
`auction_id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
`owner` VARCHAR(32) NOT NULL,
`group_id` TINYINT UNSIGNED NOT NULL ,
`title` VARCHAR(100) NOT NULL,
`sale_type` VARCHAR(1) NOT NULL,
`base_price` INT NOT NULL,
`min_increase` INT NULL,
`photo` VARCHAR(200) NULL,
`description` VARCHAR(500) NOT NULL,
`start_date` DATETIME NOT NULL,
`termination_date` DATETIME NULL,
`sold` VARCHAR(1) NOT NULL DEFAULT 0,
`purchaser` VARCHAR(32) NULL,
`deleted` VARCHAR(1) NOT NULL DEFAULT 0,
FOREIGN KEY(owner) REFERENCES users(user_name) on delete cascade on update cascade,
FOREIGN KEY(purchaser) REFERENCES users(user_name) on delete cascade on update cascade,
FOREIGN KEY(group_id) REFERENCES commodity_groups(group_id) on delete cascade on update cascade)
ENGINE=InnoDB default charset=utf8;
create table `bid`(
`bid_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
`auction_id` INT UNSIGNED NOT NULL,
`bidder` VARCHAR(32) NOT NULL,
`price` INT NOT NULL,
`date` DATETIME NOT NULL,
`deleted` VARCHAR(1) NOT NULL DEFAULT 0,
FOREIGN KEY(auction_id) REFERENCES auction(auction_id) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY(bidder) REFERENCES users(user_name) ON DELETE CASCADE ON UPDATE CASCADE)
ENGINE=InnoDB default charset=utf8;
and here is my query i use prepared statements:
SELECT `auction`.`auction_id` , `title` , `base_price` , `min_increase` , `photo` , `description` , `start_date` , `termination_date` , `max_bidder` , `bids_count` , `max_bid`
FROM `auction` , (
SELECT `bid`.`auction_id` , `bidder` AS max_bidder, `bids_count` , `max_bid`
FROM `bid` , (
SELECT `auction_id` , count( bid_id ) AS bids_count, max( price ) AS max_bid
FROM `bid`
WHERE `auction_id`
IN (
SELECT `auction_id`
FROM `auction`
WHERE `owner` = ?
)
GROUP BY (
auction_id
)
) AS temp
WHERE `bid`.`auction_id` = `temp`.`auction_id`
AND `price` = `max_bid`
) AS temp2
WHERE `auction`.`auction_id` = `temp2`.`auction_id`
it is clear that if there is no request for auction, the result will be zero and no auction will be shown to user in his profile, however he or she has just post a new auction, i will thank if any body could help me
What you have is more of a database design problem and a future scalability problem than an actual problem. You know you can make two requests if you want to.
If you care about scaling things up, you're going to have to think very carefully about what user information you want to replicate across multiple servers, and how you're going to synchronize that. The basic answer is: Yes, you use joins to include the user information you want. But a more complicated answer is that you might want to create mini tables with just a little bit of user information (duplicated and synchronized) that you can join very quickly, which no user would ever write to -- in other words they are written only by the master table either through a slave setup or with some cron job.
A lot depends on how large you expect your site to be and how many people might be writing to the users table. It's assumed that many people will be writing to the auction table, so ideally you don't want ANY foreign key dependencies on that table or you will get deadlocks. It should be an ISAM or Federated table, probably.

Polymorphic Associations or something easier

This is my first post and I can't seem to find the answer anywhere....
I have a database that has multiple companies,each company has multiple locations.
I'm running into problems trying to define the contacts. Some contacts need to be global and available
at any location....some contacts only need to exist for one location. In the contact_info table below
we specify the visibility of the contact (company or location). However the location needs to choose its primary contact.
That leaves a FK from contact -> location and from location -> contact.
I know there is another table involved but I can't seem to conceptualize it.
CREATE TABLE `company_info` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`));
CREATE TABLE `location_info` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_info` INT NOT NULL DEFAULT -1,
`name` VARCHAR(100) NOT NULL DEFAULT '',
`primary_contact_id` INT NOT NULL DEFAULT -1,
PRIMARY KEY(`id`),
UNIQUE KEY(`company_id`,`name`),
FOREIGN KEY (company_id) REFERENCES company_info(id)
FOREIGN KEY (primary_contact_id) REFERENCES contact_info(id));
CREATE TABLE `contact_info` (
`id` INT NOT NULL AUTO_INCREMENT,
`company_id` INT
`location_id` INT,
`type` ENUM('Company','Location') NOT NULL DEFAULT 'Company',
`first_name` VARCHAR(50) NOT NULL DEFAULT '',
`last_name` VARCHAR(50) NOT NULL DEFAULT '',
PRIMARY KEY(`id`),
UNIQUE KEY(`id`,`company_id`,`location_id`),
FOREIGN KEY (location_id) REFERENCES location_info(id),
FOREIGN KEY (company_id) REFERENCES company_info(id)
The most effective way would be splitting it up so that there's a table for your companies, a table with your users, and a table solely for the purpose of storing all connections (i.e. EntryID, UserID, CompanyID). This way you'll be able to easily load them afterwards.

MySQL Structure for a social network

I'm experimenting by making a social network from scratch in PHP/MySQL, but I'm having trouble thinking of the optimal MySQL structure for it, currently I have:
This is a table which stores all user info:
fname varchar (300),
sname varchar (300),
pass varchar (400),
email varchar (300),
gender varchar (300),
dob varchar (200),
uid varchar (300),
PRIMARY KEY (id)
This is created when a user signs up, their own personal table:
id int(20) NOT NULL auto_increment,
uid varchar (300),
photo_url varchar (400),
pfid varchar (300),
phototime datetime,
video_url varchar (400),
vfid varchar (300),
videotime datetime,
status longtext,
sid varchar (300),
statustime datetime,
blog longtext,
bid varchar (300),
blogtime datetime,
about_bio longtext,
about_current_job longtext,
about_secondary_school longtext,
about_primary_school longtext,
about_college longtext,
about_university longtext,
about_workemail longtext,
about_homeemail longtext,
about_phonenumber longtext,
about_relationshipstatus longtext,
about_relationshipwith longtext,
PRIMARY KEY (id)
)";
The sessions table to track whether someone is logged in or not:
id int(20) NOT NULL auto_increment,
sid varchar(300),
uid varchar(300),
PRIMARY KEY (id)
Haven't gotten onto relationships yet but I was thinking:
id int(20) NOT NULL auto_increment,
requestby varchar(200),
requestto varchar(200),
status varchar(200)
(Before anyone asks, this is purely just for the learning experience, nothing more)
Well, you definitely shouldn't have one table per user. I think a database structure more like this would work really well:
CREATE TABLE users (
userID INT NOT NULL AUTO_INCREMENT,
firstName VARCHAR(30),
lastName VARCHAR(30),
password CHAR(32), -- should be encrypted, CHAR is better if the field is always the same length
email VARCHAR(64) NOT NULL, -- not null if this is what you will use as a "username"
PRIMARY KEY (userID)
);
CREATE TABLE personalInfo (
userID INT NOT NULL,
gender ENUM ('MALE', 'FEMALE'),
dateOfBirth DATE,
phoneNumber VARCHAR(15),
personalEmail VARCHAR(64), -- may or may not be the same as the email field in the "users" table
workEmail VARCHAR(64),
bio TEXT,
FOREIGN KEY (userID) REFERENCES users (userID)
);
/* this table is not specific to any single user. It is just a list of jobs that have been created */
CREATE TABLE jobs (
jobID INT NOT NULL AUTO_INCREMENT,
company VARCHAR(100),
title VARCHAR(100),
description TEXT,
PRIMARY KEY (jobID)
);
/* the workInfo table will hold one entry per user per job. So if a user has held five jobs,
there will be five rows with that userID in this table, each with a different jobID, which
refers to an entry in the "jobs" table above. */
CREATE TABLE workInfo (
userID INT NOT NULL,
jobID INT NOT NULL,
startDate DATE,
endDate DATE, -- can set this to null if it's the user's current job
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (jobID) REFERENCES jobs (jobID)
);
CREATE TABLE schools (
schoolID INT NOT NULL AUTO_INCREMENT,
schoolName VARCHAR(100),
-- any other information you want to provide about the school (city, address, phone, etc)
PRIMARY KEY (schoolID)
);
CREATE TABLE schoolPrograms (
programID INT NOT NULL AUTO_INCREMENT,
programName VARCHAR(100),
-- any other information you want to provide about the program (department, teachers, etc)
PRIMARY KEY (programID)
);
CREATE TABLE educationInfo (
userID INT NOT NULL,
schoolID INT,
programID INT,
startDate DATE,
endDate DATE,
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (schoolID) REFERENCES schools (schoolID),
FOREIGN KEY (programID) REFERENCES schoolPrograms (programID)
);
CREATE TABLE relationships (
userID INT NOT NULL,
userID2 INT, -- allowed to be null if the user is single or does not specify who they are in a relationship with
status ENUM ('SINGLE', 'IN A RELATIONSHIP', 'MARRIED', 'IT''S COMPLICATED' /* etc */),
FOREIGN KEY (userID) REFERENCES users (userID)
);
/* each photo is created here. This way, when a user wants to share a photo,
we don't have to duplicate each column. We just create another row in
the "userPhotos" table below that) REFERENCES the same photoID. */
CREATE TABLE photos (
photoID INT NOT NULL AUTO_INCREMENT,
url VARCHAR(200),
caption VARCHAR(200),
dateOfUpload TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (photoID)
);
CREATE TABLE userPhotos (
userID INT NOT NULL,
photoID INT NOT NULL,
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (photoID) REFERENCES photos (photoID)
);
/* vidoes, handled exactly the same as photos */
CREATE TABLE videos (
videoID INT NOT NULL AUTO_INCREMENT,
url VARCHAR(200),
caption VARCHAR(200),
dateOfUpload TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (videoID)
);
CREATE TABLE userVideos (
userID INT NOT NULL,
videoID INT NOT NULL,
FOREIGN KEY (userID) REFERENCES users (userID),
FOREIGN KEY (videoID) REFERENCES videos (videoID)
);
CREATE TABLE status (
userID INT NOT NULL,
status TEXT,
FOREIGN KEY (userID) REFERENCES users (userID)
);
Don't use large varchars for all those fields. Friendship status can be just an int if you keep a lookup table (or a list in your code) that explains each value.
If the user table has an auto incrementing ID, you could use that ID for foreign key relationships. Even if you don't want UID to be an integer, you could still make it a GUID or something else that is much, much smaller than a varchar.
These tables only specify a profile and maybe a relationship, but there is so much more. Even something as simple as Twitter has a table of tweets, lists, accounts to put in a list, users that follow a list, direct messages (although those could theoretically be in the same table as Tweets), linked apps, blocked users and much, much more.
So I think first of all, you should think about what your social network should be, what it should look like, what features should it have. Then, strip that down to only the most essential features. Then, strip it down a little more, you're still thinking too big. ;)
When you got clear what your minimum desirement are, it will probably be much clearer to you what table you would need.
Don't forget to add constraints and indexes!
Note that in practice, Twitter, Facebook and the other large networks don't use MySQL at all, but to practice, MySQL is fine.

MySQL data modeling: Multiple user types / Activity / Following

I have a project in which there is a site with multiple user types. And I am having trouble wrapping my head around the best practice for this.
I want to be able to get activity from (nodes) you follow regardless of node type. Pretend the node types are:
User:
Organization:
An organization will be an entity that can act as a user. Write comments, send messages. But an organization is made up of users who can edit the orgs information. Organizations can also follow, and be followed.
A) Should Users and Organizations be separate tables?
B) Generally speaking how should this be stored.
C) If they are in fact 2 tables, how does a join work when getting activity from those you follow?
Ok, here's one possible approach.
The rough strategy here is this
Accounts (i.e., access credentials) are separate from profiles (entity-specific data)
Accounts identify the type of profile
Profiles link back to their account with a foreign key. Other related tables (comments, for example) would use account.account_id as their foreign key. Queries could then determine which profile table to use when selecting additional information.
Here's a quick ERD I knocked up with the wonderful MySQL Workbench tool.
erd http://www.shackpics.com/files/sample_erd_co3zt3y5la0l81g4m530.png
And here's the CREATE script generated by the tool for this model
SET #OLD_UNIQUE_CHECKS=##UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET #OLD_FOREIGN_KEY_CHECKS=##FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET #OLD_SQL_MODE=##SQL_MODE, SQL_MODE='TRADITIONAL';
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci ;
USE `mydb`;
-- -----------------------------------------------------
-- Table `mydb`.`account`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `account` (
`account_id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`login` VARCHAR(45) NULL ,
`password` VARCHAR(45) NULL ,
`account_type` TINYINT UNSIGNED NULL ,
PRIMARY KEY (`account_id`) )
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`organization_profile`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `organization_profile` (
`organization_profile_id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`account_id` INT UNSIGNED NOT NULL ,
`organization_name` VARCHAR(45) NULL ,
PRIMARY KEY (`organization_profile_id`) ,
INDEX `fk_organization_profile_account` (`account_id` ASC) ,
CONSTRAINT `fk_organization_profile_account`
FOREIGN KEY (`account_id` )
REFERENCES `account` (`account_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`user_profile`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `user_profile` (
`user_profile_id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`account_id` INT UNSIGNED NULL ,
`first_name` VARCHAR(45) NULL ,
`last_name` VARCHAR(45) NULL ,
PRIMARY KEY (`user_profile_id`) ,
INDEX `fk_user_profile_account1` (`account_id` ASC) ,
CONSTRAINT `fk_user_profile_account1`
FOREIGN KEY (`account_id` )
REFERENCES `account` (`account_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `mydb`.`xref_user_profile_has_organization_profile`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `xref_user_profile_has_organization_profile` (
`user_profile_id` INT UNSIGNED NOT NULL ,
`organization_profile_id` INT UNSIGNED NOT NULL ,
PRIMARY KEY (`user_profile_id`, `organization_profile_id`) ,
INDEX `fk_xref_user_profile_has_organization_profile_user_profile1` (`user_profile_id` ASC) ,
INDEX `fk_xref_user_profile_has_organization_profile_organization_pro1` (`organization_profile_id` ASC) ,
CONSTRAINT `fk_xref_user_profile_has_organization_profile_user_profile1`
FOREIGN KEY (`user_profile_id` )
REFERENCES `user_profile` (`user_profile_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_xref_user_profile_has_organization_profile_organization_pro1`
FOREIGN KEY (`organization_profile_id` )
REFERENCES `organization_profile` (`organization_profile_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
SET SQL_MODE=#OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=#OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=#OLD_UNIQUE_CHECKS;
Note: I do not advocate storing plain-text passwords. This is only a sample model to describe relationships, not cover the specifics of secure access-credential storage.
The basic strategy here is that you would arbitrarily "give" each profile table an "account_type" number. For example, organizations would be 1, and users would be 2.
Sounds like in your case organization is also an user. This is very similar to our database which looks like this,
You have a table with every users and organizations. We call them principals. The organization and user are treated the same in this table. This is where you store your data like activities. You can add a column for the type (org or user).
You would have another table for the relations. It just needs two columns, one column is organization and the other is users belong to this organization. Say an organization has 100 users, you would have 100 entries in this table for each user.

Categories