mysql没有主键

时间:2011-03-18 23:53:46

标签: mysql primary-key

我在这里有这个代码

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)

);

现在每次我输入客户的付款购买时输入他的电子邮件和金额。 问题是,每次我输入相同的电子邮件时,我都会收到主键错误(无法复制主键)

此处的主键是指包含客户个人详细信息的表格。

任何想法?

3 个答案:

答案 0 :(得分:7)

主键必须是唯一的 - 如果每个客户要进行多次付款,则不能将customer_email指定为主键。考虑添加一个单独的id列,并将其作为主键。

答案 1 :(得分:2)

我会对您的设计进行规范化,并使用存储过程按以下方式插入付款:

这里有完整的脚本:http://pastie.org/1688269

希望这会有所帮助:)

示例调用

call insert_payment('foo@bar.com',1,100);

call insert_payment('bar@foo.com',2,200);

call insert_payment('pants@elis.com',3,300);

call insert_payment('another@customer.com',1,400);

call insert_payment('another@customer.com',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| another@customer.com |
|      4 | 2011-03-19 01:34:28 |           1 | visa          | 400.00 |       4| another@customer.com |
|      3 | 2011-03-19 01:34:28 |           3 | cash          | 300.00 |       3| pants@elis.com       |
|      2 | 2011-03-19 01:34:28 |           2 | mastercard    | 200.00 |       2| bar@foo.com          |
|      1 | 2011-03-19 01:34:28 |           1 | visa          | 100.00 |       1| foo@bar.com          |
+--------+---------------------+-------------+---------------+--------+---------+----------------------+
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 ('foo@bar.com'),('bar@foo.com'),('pants@elis.com');

call insert_payment('foo@bar.com',1,100);
call insert_payment('bar@foo.com',2,200);
call insert_payment('pants@elis.com',3,300);
call insert_payment('another@customer.com',1,400);
call insert_payment('another@customer.com',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;

答案 2 :(得分: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)
);

日期是有道理的,因为这是某人可能需要/用于报告的内容。由于日期&amp;存储时间,你不太可能有相同日期值的重复(这会导致错误,就像你已经遇到的那样)。使用NOW()或ANSI标准CURRENT_TIMESTAMP在INSERT语句中填充日期值也很容易...或者您可以为列定义DEFAULT约束以在数据时自动使用当前日期插入。