2011-03-18 85 views
0

我這裏有這個代碼的MySQL沒有主鍵

drop table if exists Payments; 

create table Payments 
(
    customer_email VARCHAR(50) NOT NULL, 
    amount DOUBLE, 
    payment_type ENUM('Visa','Mastercard', 'Cash'), 

    PRIMARY KEY (customer_email), 
    FOREIGN KEY (customer_email) references customer(email) 

); 

現在每次我進入一個客戶付款買進入他的電子郵件和金額。 的概率是,每次我輸入相同的電子郵件,我得到一個主鍵錯誤(不能複製主鍵)

這裏的主鍵是指由客戶的個人詳細信息組成的表。

什麼想法?

回答

7

主鍵必須是唯一的 - 如果每個客戶將要進行多次付款,則不能將customer_email指定爲主鍵。考慮添加一個單獨的ID列,並將其作爲主鍵。

+1

'payment_id'可能是一個很好的候選人 – drudge 2011-03-18 23:57:33

+0

的概率是我給出的HTML表單,我只能輸入一個電子郵件和金額 – pantelis 2011-03-19 00:02:20

+0

payment_id將由da tabase,因此對於每個支付交易都是唯一的 – 2011-03-19 00:03:33

0

主鍵值只能在列中存在一次。爲了支持現有不止一次的價值,您:

  • 不能把(爲此事或唯一一個)主鍵約束對列
  • 使用一個以上的列作爲主鍵(被稱爲組合鍵)

我會解決你的問題,通過添加日期,有人付款:

CREATE TABLE Payments (
    customer_email VARCHAR(50) NOT NULL, 
    payment_date DATETIME, 
    amount DOUBLE, 
    payment_type ENUM('Visa','Mastercard', 'Cash'), 
    PRIMARY KEY (customer_email, payment_date), 
    FOREIGN KEY (customer_email) references customer(email) 
); 

一個日期是有道理的,因爲那是別人很可能到n eed /用於報告。由於存儲日期爲&,所以很可能不會有重複的日期值相同(這會導致錯誤,就像您遇到的錯誤一樣)。在INSERT語句中使用NOW()或ANSI標準CURRENT_TIMESTAMP ...也可以很容易地填充日期值,或者您可以爲該列定義DEFAULT約束,以便在插入數據時自動使用當前日期。

+0

沒有什麼能阻止客戶每天做多個訂單 - 同樣的問題 – MacGucky 2011-03-19 00:09:17

+0

@MacGucky:DATETIME包括時間,這在上一段中有解釋。閱讀理解FTW;) – 2011-03-19 00:12:07

+0

ups - 對不起 - 我讀日期,忽略了時間。 – MacGucky 2011-03-19 00:32:42

2

我會正常化您的設計和使用存儲過程來插入付款如下:

完整的腳本在這裏:http://pastie.org/1688269

希望這有助於:)

調用示例

call insert_payment('[email protected]',1,100); 

call insert_payment('[email protected]',2,200); 

call insert_payment('[email protected]',3,300); 

call insert_payment('[email protected]',1,400); 

call insert_payment('[email protected]',2,500); 

mysql> select * from payments_view order by pay_id desc; 
+--------+---------------------+-------------+---------------+--------+---------+----------------------+ 
| pay_id | pay_date   | pay_type_id | pay_type_name | amount | cust_id| email    | 
+--------+---------------------+-------------+---------------+--------+---------+----------------------+ 
|  5 | 2011-03-19 01:34:28 |   2 | mastercard | 500.00 |  4| [email protected] | 
|  4 | 2011-03-19 01:34:28 |   1 | visa   | 400.00 |  4| [email protected] | 
|  3 | 2011-03-19 01:34:28 |   3 | cash   | 300.00 |  3| [email protected]  | 
|  2 | 2011-03-19 01:34:28 |   2 | mastercard | 200.00 |  2| [email protected]   | 
|  1 | 2011-03-19 01:34:28 |   1 | visa   | 100.00 |  1| [email protected]   | 
+--------+---------------------+-------------+---------------+--------+---------+----------------------+ 
5 rows in set (0.00 sec) 

存儲過程

存儲過程首先檢查客戶帳戶是否已經存在,如果不存在,則創建一個然後插入支付數據。

delimiter ; 

drop procedure if exists insert_payment; 

delimiter # 

create procedure insert_payment 
(
in p_email varchar(512), 
in p_pay_type_id tinyint unsigned, 
in p_amount decimal(10,2) 
) 
begin 

declare v_cust_id int unsigned default 0; 

    if not exists (select 1 from customers where email = p_email) then 
    insert into customers (email) values (p_email); 
    set v_cust_id = last_insert_id(); 
    else 
    select cust_id into v_cust_id from customers where email = p_email; 
    end if; 

    insert into payments (cust_id, pay_type_id, amount) 
    values (v_cust_id, p_pay_type_id, p_amount); 

    select last_insert_id() as new_pay_id; 

end# 

表,視圖和觸發器

drop table if exists payments; 
drop table if exists payment_types; 
drop table if exists customers; 

create table payment_types 
(
pay_type_id tinyint unsigned not null auto_increment primary key, 
name varchar(255) unique not null 
) 
engine=innodb; 

create table customers 
(
cust_id int unsigned not null auto_increment primary key, 
email varchar(512) unique not null, 
total_amount_paid decimal(10,2) not null default 0 
) 
engine=innodb; 

create table payments 
(
pay_id int unsigned not null auto_increment primary key, 
cust_id int unsigned not null, 
pay_type_id tinyint unsigned not null, 
pay_date datetime not null, 
amount decimal(10,2) not null default 0, 
key (pay_date), 
foreign key (cust_id) references customers(cust_id), 
foreign key (pay_type_id) references payment_types(pay_type_id) 
) 
engine=innodb; 

drop view if exists payments_view; 
create view payments_view as 
select 
p.pay_id, 
p.pay_date, 
p.pay_type_id, 
pt.name as pay_type_name, 
p.amount, 
c.cust_id, 
c.email 
from 
customers c 
inner join payments p on c.cust_id = p.cust_id 
inner join payment_types pt on p.pay_type_id = pt.pay_type_id; 

delimiter # 

create trigger payments_before_ins_trig before insert on payments 
for each row 
begin 
set new.pay_date = now(); 

update customers set total_amount_paid = total_amount_paid + new.amount 
    where cust_id = new.cust_id; 
end# 

delimiter ; 

測試

insert into payment_types (name) values ('visa'),('mastercard'),('cash'); 

insert into customers (email) values ('[email protected]'),('[email protected]'),('[email protected]'); 

call insert_payment('[email protected]',1,100); 
call insert_payment('[email protected]',2,200); 
call insert_payment('[email protected]',3,300); 
call insert_payment('[email protected]',1,400); 
call insert_payment('[email protected]',2,500); 

select * from payment_types order by pay_type_id; 
select * from customers order by cust_id; 
select * from payments order by pay_id; 
select * from payments_view order by pay_id desc;