MySQL database schema: 3 columns of same type with different purpose - mysql

I am building a financial app, and it requires the following tables:
tax
item, which can have one tax
invoice, which can have many items
To the question:
An invoice must have the ability to contain 3 categories of emails:
Recipient emails
CC emails
BCC emails
So far I just have a recipients/cc/bcc column, but I don't think it's good because I'd basically have to concatenate the emails together and separate them by a comma or something.
I also thought about a generic email table, but then I'd have to create invoice_recipient_email, invoice_cc_email and invoice_bcc_email tables respectively, in order to link the emails back to the particular invoice ID as well as categorize them by the 3 types.
Can someone advice me on my second solution, or provide a better way to do this?
Here is my current schema:
CREATE TABLE tax (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
rate INT(3) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE item (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
description VARCHAR(1000) NOT NULL,
quantity INT(10) NOT NULL,
price INT(10) NOT NULL,
CONSTRAINT `f_tax_item_tax_id` FOREIGN KEY (`tax_id`) REFERENCES `tax` (`id`),
PRIMARY KEY (id)
);
CREATE TABLE invoice (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
invoice_number VARCHAR(255) NOT NULL,
recipients VARCHAR(1000) NOT NULL,
cc VARCHAR(1000) NOT NULL,
bcc VARCHAR(1000) NOT NULL,
discount INT(10) NOT NULL,
note VARCHAR(500) NOT NULL,
terms VARCHAR(2000) NOT NULL,
due_date TIMESTAMP NOT NULL,
PRIMARY KEY (id)
);

I would add a single recipients table with id (pk), invoice_id (fk), email, recipient_type fields, where recipient type could have one of the following values: to, cc, or bcc. The recipient type field would tell you how to use the email address, therefore you would not need 3 separate tables to hold the 3 different recipient types.
1 record would hold only 1 email address.

You can normalize your emails into a single table and put a flag on it to categorize its type.
CREATE TABLE invoice (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
invoice_number VARCHAR(255) NOT NULL,
discount INT(10) NOT NULL,
note VARCHAR(500) NOT NULL,
terms VARCHAR(2000) NOT NULL,
due_date TIMESTAMP NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE email(
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
invoice_id INT(10) not null references invoice(id),
email_type int not null,
addresses varchar(1000),
PRIMARY KEY (id)
);
You can define your email types in another table as well. You can look at this approach implemented in a production environment for phone numbers in MSSSQL but same concept. We however normalize the records to one phone number per record which I would also recommend you do.
CREATE TABLE [dbo].[ActorPhones](
[PKId] [int] IDENTITY(0,1) NOT NULL Primary Key,
[FKActorId] [int] NOT NULL References Actor(PKID),
[FKPhoneTypeId] [int] NOT NULL,
[Number] [varchar](20) NOT NULL
) ON [PRIMARY]
CREATE TABLE [dbo].[PhoneTypes](
[PKId] [int] IDENTITY(0,1) NOT NULL Primary Key,
[PhoneTypeName] [varchar](50) NOT NULL References ActorPhones(PKId),
[PhoneTypeDescription] [varchar](250) NULL,
[ModifiedDate] [datetime] NULL,
[ModifiedBy] [varchar](50) NULL
)

Related

VIEW created in MySQL giving wrong output with SELECT

I'm creating a database for a courtier company and I have 5 relations
CREATE TABLE Customer
(
cid int(7) NOT NULL,
cfname char(25) NOT NULL,
clname char(25) NOT NULL,
aptnum int(100) NOT NULL,
street char(50) NOT NULL,
pobox int(10) NOT NULL,
area char(50) NOT NULL,
country char(50) NOT NULL,
phone int(12) NOT NULL,
PRIMARY KEY (cid)
)ENGINE=INNODB;
CREATE TABLE Orderr
(
orderid int(8) NOT NULL,
origin char(100) NOT NULL,
destination char(100) NOT NULL,
eta date NOT NULL,
weight int(100) NOT NULL,
priority enum('F','R') NOT NULL,
task enum('P','D') NOT NULL,
odate date NOT NULL,
cnum int(12) NOT NULL,
cpin int(8) NOT NULL,
custid int(7) NOT NULL,
PRIMARY KEY (orderid),
FOREIGN KEY (custid) REFERENCES Customer(cid)
)ENGINE=INNODB;
CREATE TABLE History
(
histid int(6) NOT NULL,
orderid int(8) NOT NULL,
status enum('D','O','R') NOT NULL,
current_loc char(50) NOT NULL,
PRIMARY KEY(histid),
FOREIGN KEY (orderid) REFERENCES Orderr(orderid)
)ENGINE=INNODB;
CREATE TABLE Driver
(
driverid int(6) NOT NULL,
dfname varchar(25) NOT NULL,
dlname varchar(25) NOT NULL,
dob date NOT NULL,
phone int(10) NOT NULL,
vehicle int(6) NOT NULL,
PRIMARY KEY (driverid)
)ENGINE=INNODB;
CREATE TABLE Vehicle
(
vid int(6) NOT NULL,
num_plate varchar(6) NOT NULL,
vtype enum('T','B','P') NOT NULL,
driverr int(6) NOT NULL,
orders int(8) NOT NULL,
PRIMARY KEY (vid),
FOREIGN KEY (driverr) REFERENCES Driver(driverid),
FOREIGN KEY (orders) REFERENCES Orderr(orderid)
)ENGINE=INNODB;
I am trying to create a VIEW for the Customer giving access to specific columns, here is the query
CREATE VIEW CustView AS
SELECT cfname, clname, aptnum, street, pobox, area, country, origin, destination, weight, priority, task, eta, odate, dfname, dlname, driver.phone
FROM Customer, Orderr, Vehicle, Driver
WHERE Customer.cid=Orderr.custid AND Vehicle.driverr=Driver.driverid AND Orderr.orderid=Vehicle.orders;
When I run SELECT * FROM CustView I do not get the desired output. What changes if any should I make to my query or perhaps to my relations?
Thanks.
As the previous posters remarked, I can only guess. But from your table and view definition, I get the suspicion that you didn't model the relation between Vehicle and Order properly. A Vehicle can be used for many Orders, right? In this case, the Vehicle id must be a foreign key in the Order table. Your design is just the other way round.
Not related to your question, I am suspicious of your History table. The history of orders fulfilled comprises just those orders which are in the past, right? So the history would be just a view that selects orders by past values of some of the dates contained therein.

Duplicate data is inserted with unique index

I have a table called users with 4 unique columns and when I insert data in email it doesn't give me any error and inserts the data even when when the same value already exists in that column.
Here is my database structure:
$user = "CREATE TABLE IF NOT EXISTS users(
id INT UNSIGNED AUTO_INCREMENT,
fb_id BIGINT UNSIGNED NULL,
google_id BIGINT UNSIGNED NULL,
fname VARCHAR(255) NOT NULL,
lname VARCHAR(255) NULL,
email VARCHAR(320) NOT NULL,
username VARCHAR(20) NULL,
password VARCHAR(255) NULL,
access_token TEXT NULL,
type ENUM('facebook','google','site') NOT NULL,
gender ENUM('m','f','o') NULL,
reg_date DATE NOT NULL,
token_expire DATETIME NULL,
PRIMARY KEY(id),
UNIQUE(email,username,fb_id,google_id)
)";
But, when I create my table with following structure:
$user = "CREATE TABLE IF NOT EXISTS users(
id INT UNSIGNED AUTO_INCREMENT,
fb_id BIGINT UNSIGNED NULL UNIQUE,
google_id BIGINT UNSIGNED NULL UNIQUE,
fname VARCHAR(255) NOT NULL,
lname VARCHAR(255) NULL,
email VARCHAR(320) NOT NULL UNIQUE,
username VARCHAR(20) NULL UNIQUE,
password VARCHAR(255) NULL,
access_token TEXT NULL,
type ENUM('facebook','google','site') NOT NULL,
gender ENUM('m','f','o') NULL,
reg_date DATE NOT NULL,
token_expire DATETIME NULL,
PRIMARY KEY(id)
)";
It gives me an error when there is a duplicate entry.
Creating table with any of those methods doesn't give any error. After creating the tables I have verified with phpmyadmin that all those columns have unique index in both methods.
Akash, in the 1st create table, the composite (combination) is unique. If you want them individually to be unique, separate them into ... separate UNIQUE key statements, like in the 2nd.
Let's say the bottom of your first table read this
PRIMARY KEY(id),
UNIQUE KEY(email,username,fb_id,google_id)
Then there is nothing wrong with these two rows existing in the composite index:
'akash#gmail.com','Akash',101,102
and
'akash#gmail.com','Akash2',101,102

Split non-relational table into multiple relational tables

I have the following table of 60000 rows, in a MySQL 5 database, which is derived from a CSV file:
CREATE TABLE `smts_import` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`AscCode` varchar(5) NOT NULL,
`AscName` varchar(50) NOT NULL,
`RgnCode` varchar(5) NOT NULL,
`RgnName` varchar(100) NOT NULL,
`SCode` varchar(30) NOT NULL,
`SName` varchar(100) NOT NULL,
`AM` int(11) NOT NULL,
`AF` int(11) NOT NULL,
`LG` decimal(10,4) NOT NULL,
`LT` decimal(10,4) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `ars_codes` (`AscCode`,`RgnCode`,`SCode`),
KEY `s_code` (`SCode`)
);
and which contains much repeated data. SCodes are unique, and the relationship between the RgnCode and SCode fields is many-to-one, as is that between the AscCode and RgnCode fields.
I want to split up (normalize) the data into three separate tables in a relational manner, such that no data are repeated:
CREATE TABLE `ascs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a_code` varchar(6) NOT NULL,
`a_name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `a_code` (`a_code`)
);
CREATE TABLE `rgns` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`a_id` int(11) NOT NULL,
`r_code` varchar(6) NOT NULL,
`r_name` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `a_id`+`r_code` (`a_id`, `r_code`),
KEY `r_code` (`r_code`)
);
CREATE TABLE `sms` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`r_id` int(11) NOT NULL,
`s_code` varchar(16) NOT NULL,
`s_name` varchar(100) NOT NULL,
`a_m` int(11) NOT NULL,
`a_f` int(11) NOT NULL,
`lg` decimal(10,4) NOT NULL,
`lt` decimal(10,4) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `r_id+s_code` (`r_id`,`s_code`),
KEY `s_code` (`s_code`)
);
where rgns.a_id is a foreign key on ascs.id, and sms.r_id is a foreign key on rgns.id.
I've created the three tables and successfully populated the first two, ascs and rgns, with unique data from the smts_import table. My problem comes when I try to populate the third table sms with just the SCode, SName, AM, AF, LG and LT fields from the smts_import table, PLUS the appropriate id from the rgns table. And here I just get lost, I've tried many variations on the following:
INSERT INTO sms (r_id, s_code, s_name, a_m, a_f, lg, lt)
SELECT DISTINCT sr.id, SCode, SName, AM, AF, LG, LT
FROM sms_import AS si, rgns AS sr, ascs AS sa
WHERE (sr.r_code = si.RgnCode)
AND (sr.a_id = sa.id)
AND (sa.a_code = si.AscCode)
ORDER BY SCode
but I just end up with too many records. How do I write this insert statement to get the appropriate fields from all records from the sms_import table, plus the correct values in the sms.r_id field from the rgns.id field?
Thanks for your help
"the relationship between the RgnCode and SCode fields is many-to-one"
So you also get many rgns.id per SCode.
If you select distinct rgns.id, SCode, etc. you will get each SCode more than once depending on how many RgnCode you have for it.
I would suggest adding a id column to the sms table and create a separate table sms2rgns which contains the one-to-many relations sms.id -> rgns.id

How to make a field in a table reference to another table in MySQL/MariaDB?

Say I'm setting up an small database with just 2 tables: feeds and feeditems.
In one table I'd store the feedname and url, with an ID as unique key.
In the second table I'd like to store some info coming from feed items (in example: date, title, url of the item and feedname). But instead of storing the feed name, I'd like to reference this feed field to the ID of that feed in the first table.
Thanks
this a quick example of how to achieve your requirement...
CREATE TABLE IF NOT EXISTS `feeds` (
`Feed_ID` int(11) NOT NULL,
`Feed_Name` varchar(32) NOT NULL,
`Feed_Url` varchar(255) NOT NULL,
PRIMARY KEY (`Feed_ID`)
)
CREATE TABLE IF NOT EXISTS `feeditems` (
`FeedItem_ID` int(11) NOT NULL,
`Feed_ID` int(11) NOT NULL,
`FeedItem_Date` datetime NOT NULL,
`FeedItem_Title` varchar(255) NOT NULL,
`FeedItem_Url` varchar(255) NOT NULL,
`FeedItem_Name` varchar(255) NOT NULL,
PRIMARY KEY (`FeedItem_ID`),
FOREIGN KEY (`Feed_ID`) REFERENCES `feeds`(`Feed_ID`)
ON DELETE CASCADE
)

First Database Schema - Producing an error

This is my schema:
CREATE TABLE item (
id integer NOT NULL PRIMARY KEY AUTO_INCREMENT,
title varchar(60) NOT NULL,
description varchar(900) NOT NULL,
company_id integer NOT NULL REFERENCES company (id),
date datetime NOT NULL,
source_id integer NOT NULL REFERENCES source (id),
link varchar(255) NOT NULL,
location_id integer NOT NULL REFERENCES location (id)
);
CREATE TABLE location (
id integer NOT NULL PRIMARY KEY AUTO_INCREMENT,
name varchar(255) NOT NULL,
coordinate varchar(255) NOT NULL,
location_id integer NOT NULL REFERENCES country (id)
);
CREATE TABLE country (
id integer NOT NULL PRIMARY KEY AUTO_INCREMENT,
name varchar(255) NOT NULL
);
CREATE TABLE company (
id integer NOT NULL PRIMARY KEY AUTO_INCREMENT,
name varchar(60) NOT NULL,
);
CREATE TABLE source (
id integer NOT NULL PRIMARY KEY AUTO_INCREMENT,
name varchar(60) NOT NULL,
);
It is telling me that there is invalid syntax on line four on http://sqlfiddle.com when I put it in and click build schema. I can see no error, can anyone shed some light please?
Also if I have done anything poorly or made any bad decisions please let me know.
You have 2 faulty commas. One at the end of "CREATE TABLE company", "CREATE TABLE source".
And create country before location.
CREATE TABLE company (
id SERIAL PRIMARY KEY,
name varchar(60) NOT NULL
);
CREATE TABLE country (
id SERIAL PRIMARY KEY,
name varchar(255) NOT NULL
);
CREATE TABLE location (
id SERIAL PRIMARY KEY,
name varchar(255) NOT NULL,
coordinate varchar(255) NOT NULL,
location_id integer NOT NULL REFERENCES country (id)
);
CREATE TABLE source (
id SERIAL PRIMARY KEY,
name varchar(60) NOT NULL
);
CREATE TABLE item (
id SERIAL PRIMARY KEY,
title varchar(60) NOT NULL,
description varchar(900) NOT NULL,
company_id integer NOT NULL REFERENCES company (id),
date timestamp NOT NULL,
source_id integer NOT NULL REFERENCES source (id),
link varchar(255) NOT NULL,
location_id integer NOT NULL REFERENCES location (id)
);
You must create the tables before you can reference them elsewhere. Create your tables in this order:
Source,
Company,
Country,
Location,
Item
Note that you may do the first three in any order, but Country must come before Location, and Location, Source, and Company must come before Item.
You also have two extra commas at the end of the definitions of Source and Company. You must remove those.
Create the country table before referring to it location table.
Remove the dangling , in the definitions of company and source.
First you need to create table country then location followed by company,source and at the last item.