2011-03-18 79 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;