2015-01-26 79 views
2

我一直在学习上周的SQL,但我不确定如何在检查约束中正确添加case语句。任何人都可以给我任何指示?在检查约束中使用case语句

我有以下等级表:

CREATE TABLE Grade 
(
    salary_grade char(1) NOT NULL CHECK (salary_grade = UPPER(salary_grade)), 
     CONSTRAINT ck_grade_scale CHECK(
     CASE 
      WHEN salary_grade = '[A-D]' 
       THEN salary_scale = 'S1' 
      WHEN salary_grade = '[D-G]' 
       THEN salary_scale = 'S2' 
     END) 

     salary_scale char(2) DEFAULT 'S1' NOT NULL, 

     CONSTRAINT pk_grade PRIMARY KEY (salary_grade), 
     CONSTRAINT ck_salary_grade CHECK (REGEXP_LIKE(salary_grade, '[A-G]', 'c')), 
     --constraint must be either S1 or S2 
     CONSTRAINT ck_salary_scale CHECK (salary_scale IN ('S1', 'S2')) 
); 

我要检查,如果salary_grade为A-d之间,则salary_scale必须是“S1”,或者如果salary_grade为E-G之间那么它的“S2”。

我试图研究这一点,并拿出后者,但是它不工作..我有正确的代码结构?

+0

你得到一些错误?如果是这样,请更新您的问题,这可能有助于发现问题。 – 2015-01-26 20:38:15

+0

@Hugo Sousa我在试图放弃时失去了一个右括号。还说这个表格不存在 – user3414871 2015-01-26 20:52:11

+0

我真的很陌生,几个星期前才开始学习,所以请耐心等待 – user3414871 2015-01-26 20:52:54

回答

4

我认为你可以做到以下几点:

CREATE TABLE Grade 
(
    salary_grade char(1) NOT NULL CHECK (REGEXP_LIKE(salary_grade, '[A-G]', 'c')), 
    salary_scale char(2) DEFAULT 'S1' NOT NULL, 
    CONSTRAINT pk_grade PRIMARY KEY (salary_grade), 
    CONSTRAINT ck_grade_scale CHECK (REGEXP_LIKE(salary_grade, '[A-D]', 'c') AND salary_scale = 'S1' 
           OR REGEXP_LIKE(salary_grade, '[E-G]', 'c') AND salary_scale = 'S2') 
); 

Please see SQL Fiddle schema here.

你不需要在salary_gradeUPPER()约束,因为正则表达式的检查就足够了(你已经检查,以确保它的A和G之间的大写字母)。我不认为单独的salary_scale的约束是必要的,因为它将被包含在逻辑上,在最后一个约束中。

UPDATE

这里是你如何与一个CASE声明做到这一点:

CREATE TABLE Grade 
(
    salary_grade char(1) NOT NULL CHECK (REGEXP_LIKE(salary_grade, '[A-G]', 'c')), 
    salary_scale char(2) DEFAULT 'S1' NOT NULL, 
    CONSTRAINT pk_grade PRIMARY KEY (salary_grade), 
    CONSTRAINT ck_grade_scale CHECK (salary_scale = CASE WHEN REGEXP_LIKE(salary_grade, '[A-D]', 'c') THEN 'S1' ELSE 'S2' END) 
); 

Please see SQL Fiddle schema here.

+1

因为'ck_grade_scale'也覆盖了''salary_grade'上的第一个检查,因此也不是真的需要。 – 2015-01-26 21:47:18

+0

是的,你可能是对的,但是我必须在'CASE'中改变我的'ELSE'。严格地说,正则表达式可能比人们想象的要贵; “BETWEEN”更好。 – 2015-01-26 21:51:12

+0

@DavidFaber谢谢你,你非常有帮助。当你进入SQL时,这是一个很大的学习曲线。我认为只用几个关键词就可以很容易地学习,但事情并不像看起来那么简单 – user3414871 2015-01-27 10:56:05

3

A case必须与某些东西进行比较,这就是为什么你会得到缺少的右括号错误。除非你特别想要一个case,你可以检查结合和/或:

CONSTRAINT ck_grade_scale CHECK(
    (salary_grade BETWEEN 'A' AND 'D' AND salary_scale = 'S1') 
    OR (salary_grade BETWEEN 'D' AND 'G' AND salary_scale = 'S2')), 

SQL Fiddle demo

正如Parado所说的,您不能使用约束来有条件地设置列值,只能限制它们。您可能会使用虚拟列作为比例尺,但这意味着将查找表的一部分放入DDL而不是数据中,这似乎有点奇怪。

+0

我已经知道如何做到这一点,正如'Oracle SQL by Example'所解释的,但本书并没有告诉我如何在检查约束中使用case语句。这就是我想学的 – user3414871 2015-01-26 20:56:49

+0

@ user3414871:也许那本书并没有给你一个这种用法的例子,因为它对'CASE'不是很好用。 – Allan 2015-01-26 21:48:25

2

Check Constraints用于在插入前测试数据以保护数据结构免受假数据的影响。其实我们在select声明中使用case您不能将其用于条件插入。如果要在插入之前更改特定列的数据,则需要使用trigger,或者也可以使用virtual column,但它有一些限制。

的更多信息,你可以在这里找到

+0

好的。这有助于..谢谢。我在想的是,如果输入等级,那么salary_scale会自动放入。这可能吗? – user3414871 2015-01-26 21:03:01

+1

@ user3414871是的,可以通过使用触发器或虚拟列,如上所述。 – Parado 2015-01-26 21:06:25

+0

好的..我不是试图给列赋值,只是试图确保列的值是S1或S2。即S1等级A – user3414871 2015-01-26 21:23:27