好的,我被要求准备一个大学数据库,我需要以某种方式存储某些数据。 例如,我需要存储一个包含字母后跟两个整数的课程代码。例如。 I45,D61等。 所以它应该是VARCHAR(3)我是对的吗?但我仍然不确定这是否是正确的道路。我也不确定我将如何在SQL脚本中强制执行此操作。 我似乎无法在笔记中找到任何答案,而且我正在编写这个问题的数据字典,然后我才会插入脚本。
任何提示?
答案 0 :(得分: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
);
这种方法的优点是,当未来学校扩展时,他们决定提供西班牙语语言数据库结构,您的数据库与用户引入的用户解释值隔离。< / p>
假设您的数据库使用智能密钥启动:
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-D61 , ESP: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,也可能导致开发人员的麻烦。
如果您从一开始就使用dumb主键开始,即使用户在您不知情的情况下向系统引入规则,也不会导致任何大量数据更改或数据架构更改到您的数据库设计。这可以让你花时间相应地调整你的申请。如果您将智能放在主键中,那么上面的用户需求可以使您的主键自然地转移到复合主键。这不仅对数据库设计重组和数据的大规模更新很困难,您也很难快速调整应用程序以适应新的数据库设计。
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规则拆分为两个字段,这些字段不需要对依赖表进行更改。如果使用智能复合主键,则重构数据将迫使您将复合主键上的更改级联到从属表的复合外键。使用哑主键,您的应用程序仍然可以照常运行,您可以随时根据新设计(例如新文本框,课程语言)修改应用程序的更改。使用哑主键,从属表不需要复合外键指向课程表,他们仍然可以使用相同的旧哑/代理主键
使用哑主键时,主键和外键的大小不会扩展
答案 1 :(得分: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
BTW:对于“实际”PK,我可能会使用代理ID。但上面的域(使用UNIQUE约束)可以作为“逻辑”候选键。
这基本上是表是域范例的结果。
答案 2 :(得分:1)
我强烈建议您不要对数据类型过于具体,因此VARCHAR(8)
之类的内容会没问题。原因是:
check
约束(希望“验证”这些值),但是它们会被忽略并且仅出于兼容性原因而被允许在系统的所有组件中,数据库架构始终是最难改变的,因此在数据类型中允许一些灵活性以尽可能避免更改。