MySql: The customer has multiple addresses only one is primary - mysql

I don't think I planned and organized the table well, so please consider and advise me how to solve this.
In my application I have to ensure that customers can have multiple addresses only one of those addresses must be marked as primary. The primary address is used as the delivery address, etc.
I have customer table and i create new relation table customer_addresses.
CREATE TABLE `customer_addresses` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`custemer_id` int(11) DEFAULT NULL,
`primary_adddrss` tinyint(1) DEFAULT NULL,
`address` varchar(225) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `custemer_id_UNIQUE` (`custemer_id`),
UNIQUE KEY `primary_UNIQUE` (`primary_adddrss`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
This table must contain all the addresses of all customers but only one address from a specific customer must be primary and customer can have only one primary address. That is reson whay i put two unique index.
If i remove custemer_id unique only one primary address can be in whole table for all customers.
Only one primary address per customer other non-primary addresses are null.
Table
id | customer_id | primary_address | address
--------------------------------------------------------
1 1 1 Test
This above customer have only one primary address. Now i want to insert for the some customer more non-primary addresses.
When i try to insert
INSERT INTO `table`.`customer_addresses`(`id`,`custemer_id`,`primary_adddrss`,`address`)
VALUES (1, null ,'Test 2');
I get error
1062: Duplicate entry '1' for key 'primary_UNIQUE'
If i remove primary_UNIQUE than all cusomers can have only one primary. I need one customer only one primary.
How to redesign table to slove this?
Thanks

If the customer may have a lot of different addresses then you have 1:N relation. Create separate addresses table which refers to customers table. Add a column which marks primary address and restrict with only one mark per customer_id.
Schematically (no syntax):
CREATE TABLE customer ( customer_id PRIMARY KEY, ... );
CREATE TABLE address ( address_id PRIMARY KEY,
-- reference to customer
customer_id NOT NULL REFERENCES customer (customer_id),
-- can be either 1 or NULL
is_primary BOOLEAN NULL CHECK (is_primary = 1),
-- allows one 1 and many NULL per customer
UNIQUE (customer_id, is_primary),
... );
DEMO

Option 1 :
CREATE TABLE `customer_addresses` ( `id` INT NOT NULL AUTO_INCREMENT ,
`customer_id` INT NOT NULL ,
`primary_address` TEXT NOT NULL ,
`addresses` TEXT NOT NULL ,
PRIMARY KEY (`id`)) ENGINE = InnoDB;
you can save primary address in primary_address column, and other addresses is saved in addresses column as array
Option 2 :
CREATE TABLE `customer_addresses` ( `id` INT NOT NULL AUTO_INCREMENT ,
`customer_id` INT NOT NULL ,
`is_primary` BOOLEAN NOT NULL ,
`addresses` TEXT NOT NULL ,
PRIMARY KEY (`id`)) ENGINE = InnoDB;
just save all address as usual, and marks the primary address with is_primary=1 and the non-primary address with is_primary=0

Related

MySQL one to many with primary choice

Say I have a bunch of people with multiple phone numbers. In a MySQL database I'd have a Person table and a Phone Number table with a many to one relationship.
Now I want to make one of those numbers the primary phone number and only allow one primary number per person. How would I model this?
Try the schema below. It will prevent entries that try to assign more than one primary number per person.
CREATE TABLE person (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`first_name` VARCHAR(50) NOT NULL,
`last_name` VARCHAR(50) NOT NULL,
PRIMARY KEY(`id`)
);
CREATE TABLE phonenumber (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`phonenumber` VARCHAR(10) NOT NULL,
`person_id` INT(11) UNSIGNED NOT NULL,
`is_primary` ENUM('1'),
PRIMARY KEY(`id`),
UNIQUE KEY idx_person_primary (`person_id`, `is_primary`),
UNIQUE KEY idx_person_phone (`phonenumber`, `person_id`)
);
INSERT INTO person (first_name, last_name) VALUES ('Michael', 'Jones');
INSERT INTO phonenumber (phonenumber, person_id, is_primary) VALUES ('9876543210', 1, 1);
INSERT INTO phonenumber (phonenumber, person_id, is_primary) VALUES ('1234567890', 1, NULL);
INSERT INTO phonenumber (phonenumber, person_id, is_primary) VALUES ('1234567891', 1, NULL);
This will allow the DB to police a single primary phone number for each person. For example if you try to assign another primary phone number to Michael Jones:
INSERT INTO phonenumber (phonenumber, person_id, is_primary) VALUES ('0123211234', 1, 1);
You will get a "Duplicate entry '1-1' for key 'idx_person_primary'" error.
http://sqlfiddle.com/#!9/dbb3c7/1
The "exactly one primary phone number" is tricky. One way uses triggers. Other databases offer expression-based indexes. This is tricky because:
The constraint spans two tables.
Guaranteeing exact "one-ness" across updates is tricky.
But one method in MySQL that comes close and doesn't use triggers:
create table persons (
personId int auto_increment primary key,
primary_personPhonesId int,
. . .
);
create table personPhones (
personPhonesId int auto_increment primary key,
personId int,
. . .
foreign key (personId) references persons (personId),
unique (personId, personPhonesId) -- seems redundant but needed
);
alter table persons
add foreign key (personId, primary_personPhonesId) on personPhones(personId, personPhonesId);
It is tempting to declare primary_personPhonesId as not null. However, that makes it difficult to insert rows into the two tables.
An alternative method uses computed columns:
create table persons (
personId int auto_increment primary key,
. . .
);
create table personPhones (
personPhonesId int auto_increment primary key,
personId int,
isPrimary boolean,
. . .
foreign key (personId) references persons (personId),
primaryId as (case when isPrimary then personPhonesId end),
unique(primaryId)
);
Similar to the previous solution, this does not guarantee that isPrimary is always set.
You can try the below mentioned design:
Person (Id (PK),name,....)
TelephoneNumber (Id(PK), telNo, PersonId(FK))
PrimaryTelNo (PersonId(FK), TelId(FK))
You can create a table showing mapping of TelId and PersonId and declare the combination of TelId and PersonId as composite primary key
The simplest way is to make the 'first' one primary, but this becomes tricky when you want to change which one is primary. In that case, I believe you can do this...
CREATE TABLE my_table
(person_id INT NOT NULL
,phone VARCHAR(12) not null
,is_primary enum('1') null
,primary key(person_id,phone)
, unique (person_id,is_primary)
);
INSERT INTO my_table VALUES
(1,'123',1),
(1,'234',null),
(1,'345',null),
(2,'456',null),
(2,'567',1),
(2,'678',null);
So, the enum allows values of 1 and null, but while there can be several nulls, there can only be one '1' per person. However, this solution doesn't preclude the possibility that none of the numbers are primary!
You should create a third table person_primary_number with only two fields:
person_id
phone_number_id
In this table you should insert the ids of the person and his primary number. The primary key of this table is on these two columns.
Another way is to add primary_number_id directly to the person table. This is probably the simplest solution.
Then you should have:
person
—————-
id (primary key int autoincrement)
primary_number_id (foreign key for phone_number.id)
name
...
phone_number
———————————-
id (primary key int autoincrement)
person_id (foreign key for person.id)
phone_number
The only problem with this solution is that you can assign as primary phone the number of somebody else.
This violates a strong principle of schema design -- don't pack a list into a cell. But...
If you only need to display the phone number to some human who will be doing a call, and
If that human possibly needs to see non-primary numbers, then
Consider having a VARCHAR(100) column that has a commalist that starts with the 'primary' phone number and continues with alternative numbers.
Note that the application would be responsible for putting the list together, and dealing with updates. Or you could push this back onto the user by providing a UI that asks for "phone number(s), starting with the preferred one to call you with; please separate with commas."

Inserting into multiple tables at once

Structure:
Table A)
CREATE TABLE Item (
Id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'Unique id of an item',
`By` VARCHAR(50) DEFAULT NULL,
PRIMARY KEY (Id),
CONSTRAINT FK_Item_User_Name FOREIGN KEY (`By`)
REFERENCES User(Name) ON DELETE NO ACTION ON UPDATE CASCADE
)
Table B)
CREATE TABLE ItemName (
Item_Id INT(11) UNSIGNED NOT NULL COMMENT 'Item id this name is referencing',
Language VARCHAR(5) NOT NULL COMMENT 'language code by ISO 639-2/T',
Translation VARCHAR(50) NOT NULL COMMENT 'Item name for given language',
PRIMARY KEY (Item_Id, Language),
CONSTRAINT FK_ItemName_Item_Id FOREIGN KEY (Item_Id)
REFERENCES Item(Id) ON DELETE CASCADE ON UPDATE CASCADE
)
Table C)
CREATE TABLE User (
Name VARCHAR(50) NOT NULL,
Password VARCHAR(50) NOT NULL,
Salt VARCHAR(255) NOT NULL,
Blocked TINYINT(1) DEFAULT 0,
PRIMARY KEY (Name),
UNIQUE INDEX UK_User_Name (Name)
)
Question:
Now I want to insert a new item. Let's say the user provides us with:
Translation
Language code
Username
What i got so far:
I was thinking of puting it in a transaction and inserting into each table after eachother. But then i'm stuck on how do i know what Item.Id to use in the ItemName.Item_Id field since the Item table will AI a new Id for the insert.
I could get the last Item.Id, but then it might be pointing to another item if multiple users were to be inserting a new item simulaneuosly.
ps. Engine=InnoDB
BEGIN;
INSERT into one table;
get the last_insert_id() -- there are many ways to do this, depending on the API
INSERT into next table...
... ;
COMMIT;
Do the inserts in the order that avoids violating your FOREIGN KEYs.

Using group of columns as a unique key in MySQL

I have a table called requests on which the columns are id, placeId, songId, userId
id is the primary index of the table. Rest of the columns are only unsigned integers and no other unique key is defined.
I want placeId & songId pairs to be unique, i.e., if a row has placeId : 5 and songId : 12, no other rows can have the same combination.
I want this check to happen in SQL level, so that I can query like insert into requests (...) values (...) on duplicate key do something else
you can create a UNIQUE index on multiple columns like this
CREATE UNIQUE INDEX placeSong
ON requests (placeId, songId)
Another method is to add an unique constraint to the table :
ALTER TABLE requests ADD CONSTRAINT placeSong UNIQUE( placeId , songId );
CREATE TABLE `tbl` (
`ID` INT(11) NOT NULL AUTO_INCREMENT,
`field1` VARCHAR(45) NOT NULL DEFAULT '',
`field2` VARCHAR(20) NOT NULL DEFAULT '',
PRIMARY KEY (`ID`),
UNIQUE INDEX `Index 2` (`field1`, `field2`)
);

Mysql Foreign Key Usage

I'm trying my first hand at creating a mysql database for a simple blog. I'm having trouble understanding foreign keys and their appropriate relations. If someone can explain in "layman's" terms I'll be very happy.
I have a table called users that has the basics of fields (username, email, password etc) which I've created a user_type field and set it to INT. I've created the corresponding table called user_type and added two fields (one being the type_id = primary key and the other been the type = VARCHAR).
My question is:
Am I correct in understanding that I connect the two tables together by setting the foreign key link from the user_type INT in the users table to reference the type_id from the user_type table?
Your understanding is correct.
From SQL FOREIGN KEY Constraint
A FOREIGN KEY in one table points to a PRIMARY KEY in another table.
So in your example, the user_type id in table user_types would be the primary key, and the user_type int in table users would be the foreign key entry.
This enforces that an entry in table user_types has to exist before it can be used in table users.
You referencing from user to usertype:
n users have one user_type
If you create the table with an sql statement it should include something like this in the user part:
DROP TABLE IF EXISTS `user` ;
CREATE TABLE IF NOT EXISTS `user` (
`ID` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR(55) NOT NULL ,
`email` VARCHAR(55) NOT NULL ,
`password` VARCHAR(55) NOT NULL ,
`user_type` INT NOT NULL ,
PRIMARY KEY (`ID`) ,
INDEX `user_to_usertype_idx` (`user_type` ASC) ,
CONSTRAINT `user_to_usertype`
FOREIGN KEY (`user_type` )
REFERENCES `user_type` (`type_id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
You have to create user_type before you create user, otherwise you will get a failure.

MySQL unique id across multiple tables

I have 2 tables with the following structure:
CREATE TABLE IF NOT EXISTS `car` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(255) NOT NULL ,
`title` VARCHAR(255) NOT NULL
PRIMARY KEY (`id`) ,
UNIQUE INDEX `name_UNIQUE` (`name` ASC) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `book` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(255) NOT NULL ,
`title` VARCHAR(255) NOT NULL
PRIMARY KEY (`id`) ,
UNIQUE INDEX `name_UNIQUE` (`name` ASC) )
ENGINE = InnoDB;
I generating the name column from the title for example: if title: Foo Bar -> name: foo-bar. I'm using this value in the URL. Eariler i had URLs like this /car/foo-bar or /book/foo-bar having same name value in both table wasnt a problem. But i want shorter URLs now: /foo-bar or /foo-bar-2.
How can I make the name value unique across multiple tables?
If you're building an OO application, you would put the name in a separate table and add foreign keys from books and cars to "names"... or whatever that table means in your application, for example product.
Otherwise you can enforce it with triggers, but I don't know how triggers work in mysql.
If you want to force it to be unique, then you could create a third table called name_reference for example with a prinary key of the combination of the fields name and a field called type. Then you could have book and car have foreign keys to the name_reference.