1

好的,我被要求准备一个大学数据库,并且我需要以某种方式存储某些数据。例如,我需要存储一个课程代码,该课程代码包含一个字母,后跟两个整数。例如。I45、D61等 所以应该是 VARCHAR(3) 对吗?但我仍然不确定这是否是正确的道路。我也不确定如何在 SQL 脚本中执行此操作。我似乎在我的笔记中找不到任何答案,我目前正在为这个问题编写数据字典,然后再介入脚本。

有小费吗?

4

3 回答 3

4

尽可能做没有业务意义的主键。您可以轻松更改数据库设计,而不会严重影响应用程序层。使用哑主键,用户不会将含义与某个记录的标识符相关联。

您所查询的内容被称为智能钥匙,通常是用户可见的。非用户可见的键称为哑键或代理键,有时这个非用户可见的键变得可见,但这不是问题,因为大多数哑键不是由用户解释的。一个例子,但是你想改变这个问题的标题,这个问题的 id 将保持不变https://stackoverflow.com/questions/10412621/

使用智能主键,有时出于审美原因,用户希望指定键的格式和外观。这可以很容易地根据用户的感受经常更新。这将是应用程序方面的一个问题,因为这需要级联相关表的更改;和数据库方面也是如此,因为相关表上键的级联更新非常耗时

在此处阅读详细信息:

http://www.bcarter.com/intsurr1.htm


代理键的优点:http ://en.wikipedia.org/wiki/Surrogate_key

您可以在代理键(又名哑键)旁边实现自然键(又名智能键)

-- Postgresql has text type, it's a character type that doesn't need length, 
-- it can be upto 1 GB
-- On Sql Server use varchar(max), this is upto 2 GB

create table course
(
    course_id serial primary key, -- surrogate key, aka dumb key

    course_code text unique, -- natural key. what's seen by users e.g. 'D61'

    course_name text unique, -- e.g. 'Database Structure'
    date_offered date
);

这种方法的优点是,当学校在未来某个时间点扩展时,他们决定提供一个面向西班牙语的数据库结构,您的数据库与用户引入的用户解释值隔离。

假设您的数据库开始使用智能密钥:

create table course
(
    course_code primary key, -- natural key. what's seen by users e.g. 'D61'

    course_name text unique, -- e.g. 'Database Structure'
    date_offered date
);

然后是西班牙语的数据库结构课程。如果用户将他们自己的规则引入您的系统,他们可能会想在 course_code 值上输入这个: D61/ESP,其他人会这样做ESP-D61ESP:D61。如果用户决定自己的主键规则,事情可能会失控,然后他们会告诉你根据他们在主键格式上创建的任意规则查询数据,例如“列出所有西班牙语我们在这所学校提供的课程”,不是史诗般的要求吗?那么一个优秀的开发人员会做些什么来适应数据库设计的这些变化呢?他/她将形式化数据结构,将表重新设计为:

create table course
(
    course_code text, -- primary key
    course_language text, -- primary key

    course_name text unique,
    date_offered date,

    constraint pk_course primary key(course_code, course_language)
);

你看到这个问题了吗?这将导致停机,因为您需要将更改传播到依赖于该课程表的表的外键。当然,您还需要首先调整那些依赖表。看看它不仅会给 DBA 带来麻烦,也会给开发人员带来麻烦。

如果您从一开始就使用哑主键,即使用户在您不知情的情况下向系统引入规则,这也不会导致您的数据库设计发生任何大量数据更改或数据架构更改。这可以为您争取时间来相应地调整您的应用程序。然而,如果您将智能放入主键中,则上述用户需求可以使您的主键自然地演变为复合主键。这不仅对数据库设计重组和数据的大量更新很困难,而且您也很难让您的应用程序快速适应新的数据库设计。

create table course
(
    course_id serial primary key,
    course_code text unique, -- natural key. what's seen by users e.g. 'D61'
    course_name text unique, -- e.g. 'Database Structure'
    date_offered date
);

因此,使用代理键,即使用户将新规则或信息存储到 course_code 中,您也可以安全地对表进行更改,而无需强迫您快速调整应用程序以适应新设计。您的应用程序仍然可以继续运行,并且不需要停机。它真的可以让您有时间随时相应地调整您的应用程序。这将是对特定语言课程的更改:

create table course
(
    course_id serial primary key,

    course_code text, -- natural key. what's seen by users e.g. 'D61'
    course_language text, -- natural key. what's seen by users e.g. 'SPANISH'

    course_name text unique, -- e.g. 'Database Structure in Spanish'
    date_offered date,

    constraint uk_course unique key(course_code, course_language)
);

如您所见,您仍然可以执行大量UPDATE语句来将用户对 course_code 施加的规则拆分为两个字段,这不需要对相关表进行更改。如果您使用智能复合主键,重组数据将迫使您将复合主键上的更改级联到依赖表的复合外键。使用哑主键,您的应用程序仍将照常运行,您可以在以后随时根据新设计(例如新文本框,用于课程语言)修改对应用程序的更改。使用哑主键,依赖表不需要复合外键来指向课程表,它们仍然可以使用相同的旧哑/代理主键

而且使用哑主键,主键和外键的大小不会扩大

于 2012-05-02T11:22:18.963 回答
2

这是域解决方案。仍然不完美,检查可以改进等。

set search_path='tmp';

DROP DOMAIN coursename CASCADE;
CREATE DOMAIN coursename AS varchar NOT NULL
    CHECK (length(value) > 0
    AND  SUBSTR(value,1) >= 'A' AND SUBSTR(value,1) <= 'Z'
    AND  SUBSTR(value,2) >= '0' AND SUBSTR(value,2) <= '9' )
    ;

DROP TABLE course CASCADE;
CREATE TABLE course
    ( cname coursename PRIMARY KEY
    , ztext varchar
    , UNIQUE (ztext)
    );
INSERT INTO course(cname,ztext) 
  VALUES ('A11', 'A 11' ), ('B12', 'B 12' ); -- Ok
INSERT INTO course(cname,ztext)
  VALUES ('3','Three' ), ('198', 'Butter' ); -- Will fail

顺便说一句:对于“实际”PK,我可能会使用代理 ID。但是上面的域(具有 UNIQUE 约束)可以用作“逻辑”候选键。

这基本上是Table is Domain范式的结果。

于 2012-05-02T11:53:41.457 回答
1

我强烈建议您不要对数据类型过于具体,这样VARCHAR(8)就可以了。原因是:

  • 明年代码中可能有四个字符。业务需求一直在变化,所以不要过多地锁定字段长度
  • 让应用层处理验证——毕竟,它必须将验证问题传达给用户
  • 通过将其限制为 3 个字符,您几乎没有增加商业价值
  • 使用 mysql,虽然您可以在列上定义 check约束(希望“验证”值),但它们被忽略并且仅出于兼容性原因允许

在系统的所有组件中,数据库模式始终是最难更改的,因此请允许您的数据类型具有一定的灵活性,以尽可能避免更改。

于 2012-05-02T12:04:26.750 回答