【问题标题】:Adding a column with default value of the date of the day after tomorrow添加具有后天日期默认值的列
【发布时间】:2015-04-21 14:19:24
【问题描述】:

我在大学的数据库课程中使用 Mysql Workbench,尽管它使用起来非常简单,但有些事情我无法解决。

现在,我一直在尝试建立一个类似于 Blockbuster 的商店。在我的租赁页面上,我想添加一个 Exp_Ret_Date、Act_Ret_Date 和 Book_Date。现在,Book_Date 和 Exp_Ret_Date 都有两个默认值:Book_Date 是 NOW(),而 Exp_Ret_Date 应该是 Book_Date 之后的 2 天。

所以,我尝试在 Default camp 上写 DATE_ADD(NOW(), INTERVAL 2 DAY),但它不起作用。我尝试使用 TIMESTAMP、CURDATE、ADDDATE 和其他任何我能想到的东西,但效果不佳。所以,如果有人能告诉我我能做些什么来解决这个问题,我和我的同学们会非常开心。

这是 MySQL Workbench 生成的全部代码。它一直说在 DATE_ADD 部分的行中有语法错误。

-- MySQL Workbench Forward Engineering

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
USE `mydb` ;

-- -----------------------------------------------------
-- Table `mydb`.`MEMBER`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`MEMBER` (
  `MEMBER_ID` INT(10) NOT NULL,
  `LAST_NAME` VARCHAR(25) NOT NULL,
  `FIRST_NAME` VARCHAR(25) NULL,
  `ADDRESS` VARCHAR(100) NULL,
  `CITY` VARCHAR(30) NULL,
  `PHONE` VARCHAR(15) NULL,
  `JOIN_DATE` DATETIME NOT NULL DEFAULT NOW(),
  PRIMARY KEY (`MEMBER_ID`),
  UNIQUE INDEX `MEMBER_ID_UNIQUE` (`MEMBER_ID` ASC))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`TITLE`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`TITLE` (
  `TITLE_ID` INT(10) NOT NULL,
  `TITLE` VARCHAR(60) NOT NULL,
  `DESCRIPTION` VARCHAR(400) NOT NULL,
  `RATING` ENUM('G','PG','R','NC17','NR') NULL,
  `CATEGORY` ENUM('DRAMA','COMEDY','ACTION','CHILD','SCIFI','DOCUMENTARY') NULL,
  `RELEASE_DATE` DATETIME NULL,
  PRIMARY KEY (`TITLE_ID`),
  UNIQUE INDEX `TITLE_ID_UNIQUE` (`TITLE_ID` ASC))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`TITLE_COPY`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`TITLE_COPY` (
  `COPY_ID` INT(10) NOT NULL,
  `STATUS` ENUM('AVAILIBLE','DESTROYED','RENTED','RESERVED') NOT NULL,
  `TITLE_ID` INT(10) NOT NULL,
  PRIMARY KEY (`COPY_ID`, `TITLE_ID`),
  UNIQUE INDEX `COPY_ID_UNIQUE` (`COPY_ID` ASC),
  INDEX `fk_TITLE_COPY_TITLE_idx` (`TITLE_ID` ASC),
  CONSTRAINT `fk_TITLE_COPY_TITLE`
    FOREIGN KEY (`TITLE_ID`)
    REFERENCES `mydb`.`TITLE` (`TITLE_ID`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`RENTAL`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`RENTAL` (
  `BOOK_DATE` DATETIME NOT NULL DEFAULT NOW(),
  `ACT_RET_DATE` DATETIME NULL,
  `EXP_RET_DATE` DATETIME NULL DEFAULT NOW() + INTERVAL 2 DAY,
  `MEMBER_ID` INT(10) NOT NULL,
  `COPY_ID` INT(10) NOT NULL,
  `TITLE_ID` INT(10) NOT NULL,
  PRIMARY KEY (`BOOK_DATE`, `COPY_ID`, `TITLE_ID`, `MEMBER_ID`),
  UNIQUE INDEX `BOOK_DATE_UNIQUE` (`BOOK_DATE` ASC),
  INDEX `fk_RENTAL_MEMBER1_idx` (`MEMBER_ID` ASC),
  INDEX `fk_RENTAL_TITLE_COPY1_idx` (`COPY_ID` ASC, `TITLE_ID` ASC),
  CONSTRAINT `fk_RENTAL_MEMBER1`
    FOREIGN KEY (`MEMBER_ID`)
    REFERENCES `mydb`.`MEMBER` (`MEMBER_ID`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_RENTAL_TITLE_COPY1`
    FOREIGN KEY (`COPY_ID` , `TITLE_ID`)
    REFERENCES `mydb`.`TITLE_COPY` (`COPY_ID` , `TITLE_ID`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`RESERVATION`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `mydb`.`RESERVATION` (
  `RES_DATE` DATETIME NOT NULL DEFAULT NOW(),
  `MEMBER_ID` INT(10) NOT NULL,
  `TITLE_ID` INT(10) NOT NULL,
  PRIMARY KEY (`RES_DATE`, `MEMBER_ID`, `TITLE_ID`),
  INDEX `fk_RESERVATION_MEMBER1_idx` (`MEMBER_ID` ASC),
  INDEX `fk_RESERVATION_TITLE1_idx` (`TITLE_ID` ASC),
  CONSTRAINT `fk_RESERVATION_MEMBER1`
    FOREIGN KEY (`MEMBER_ID`)
    REFERENCES `mydb`.`MEMBER` (`MEMBER_ID`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION,
  CONSTRAINT `fk_RESERVATION_TITLE1`
    FOREIGN KEY (`TITLE_ID`)
    REFERENCES `mydb`.`TITLE` (`TITLE_ID`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

提前感谢您提供的任何帮助。错误在第 72 行附近。

【问题讨论】:

  • DEFAULT 不能是表达式,它必须是文字(或 CURRENT_TIMESTAMP 作为特殊例外)。如果您想用计算值自动填充字段,请使用触发器。

标签: mysql mysql-workbench


【解决方案1】:

UNIQUE INDEX 定义是多余的,大部分都不需要。

例如,MEMBER_ID 已经定义为PRIMARY KEY;以该列作为前导列的第二个唯一索引实际上并不是必需的。

PRIMARY KEY (`MEMBER_ID`),
UNIQUE INDEX `MEMBER_ID_UNIQUE` (`MEMBER_ID` ASC))

我可以理解 InnoDB 不会抛出异常;一些查询可能能够使用“窄”索引,但这是一个罕见的用例,第二个索引实际上可以提高性能。同样的事情也适用于这里:

PRIMARY KEY (`TITLE_ID`),
UNIQUE INDEX `TITLE_ID_UNIQUE` (`TITLE_ID` ASC))

UNIQUE INDEX 是多余的,因为 TITLE_ID 已定义为表的唯一群集键。

这有点奇怪,COPY_ID 是唯一的,但 PRIMARY KEY 被定义为该唯一列和第二列的组合:

PRIMARY KEY (`COPY_ID`, `TITLE_ID`),
UNIQUE INDEX `COPY_ID_UNIQUE` (`COPY_ID` ASC),

COPY_ID 设置为表的PRIMARY KEY 就足够了。这同样适用...

PRIMARY KEY (`BOOK_DATE`, `COPY_ID`, `TITLE_ID`, `MEMBER_ID`),
UNIQUE INDEX `BOOK_DATE_UNIQUE` (`BOOK_DATE` ASC),

但在这种情况下,我怀疑BOOK_DATE 实际上并不是唯一的。如果是,则不需要复合主键。


要让数据库在插入行时自动为列分配值,您可以定义BEFORE INSERT 触发器。 (正如 Barmar 在他的评论中指出的那样,MySQL 在接受什么作为 DEFAULT 值方面受到限制......它必须是 literal 值,它不能是表达式。(有一个小例外对于 CURRENT_TIMESTAMP 对于 TIMESTAMP 列;过去只能在数据类型为 TIMESTAMP 的列上执行此操作,但我认为 MySQL 的最新版本支持 `DATETIME 列的类似内容。)

作为一个简单的触发器示例:

DELIMITER $$

CREATE TRIGGER mytable_bi 
BEFORE INSERT ON mytable
FOR EACH ROW
BEGIN
  SET NEW.exp_ret_date = NOW() + INTERVAL 2 DAY;
END$$

DELIMITER ;

触发器将覆盖提供的任何值。您可以在触发器中执行条件测试,以检查列值是否为 NULL,然后再为其分配值:

  IF NEW.exp_ret_date IS NULL THEN
    SET NEW.exp_ret_date = NOW() + INTERVAL 2 DAY;
  END IF;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    相关资源
    最近更新 更多