Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 中间可选模型的基础数据库设计_Sql_Ruby On Rails_Database_Database Design - Fatal编程技术网

Sql 中间可选模型的基础数据库设计

Sql 中间可选模型的基础数据库设计,sql,ruby-on-rails,database,database-design,Sql,Ruby On Rails,Database,Database Design,我正在从事一个项目,在这个项目中,我在设计一个看似非常简单的场景时遇到了一些小困难: 用户属于属于国家的城市,但是,城市引用可能为空,而用户必须属于国家。换句话说(在基本RoR模型语法中) #类用户

我正在从事一个项目,在这个项目中,我在设计一个看似非常简单的场景时遇到了一些小困难:

用户
属于属于
国家
城市
,但是,
城市
引用可能为
,而
用户
必须属于
国家
。换句话说(在基本RoR模型语法中)

#类用户

我对这种超级简单设计的问题是,有太多的冗余。只要一个
城市
用户
引用,就可以从中推断出
国家
引用(换句话说,因为它已经在
城市
表中被引用了,所以在
用户
表中也引用它似乎不是那么可怕)。

我没有深思熟虑的答案,但我首先想到的是

# class User < ActiveRecord::Base 
belongs_to :country, :through => :city
validates_existence_of :city

# class City < ActiveRecord::Base
has_many :users
belongs_to :country
validates_existence_of :country

# class Country < ActiveRecord::Base
has_many :users, :through => :city
has_many :cities
#类用户:城市
验证是否存在:城市
#class City:城市
有很多城市吗

诀窍是在每个国家/地区添加一个虚拟或空白城市,以便验证有效。

当a(城市)也唯一标识B(国家)时,会发生这种情况,但a是可选的,而B是强制性的。基本上,之所以添加Country,是因为City是可选的,而仍然需要标识每个用户的国家/地区

将国家和城市联系在一起的想法可能看起来很有吸引力,因为一个城市独特地“识别”了一个国家,但是:是吗?你知道,阿姆斯特丹不仅仅是荷兰的一个城市

另外,它带来了你在评论中已经提到的问题。。。您如何处理附加数据;而将这些国家列为此类国家现在需要将它们从国家/城市合并中过滤出来


您的原始设计可能会觉得冗余和数据方面的冗余,但逻辑方面和需求方面的冗余则不然。我会坚持它,因为它非常清楚,完美地反映了需求。我将学会忍受明显的冗余。你为避免“冗余”而提出的任何“解决方案”,最终都可能会把事情弄得一团糟。或者将使将来定义查询变得更加困难。

出于某种原因,这有“sql”标记,因此我在sql中是这样做的(注意,整个sql中都有引用整数,没有
NULL
able列):

测试数据:

INSERT INTO Countries (country_code) VALUES 
('ITL'), 
('ESP');

INSERT INTO Cities (city_name, country_code) 
VALUES 
('Roma', 'ITL'), 
('Naples', 'ITL'), 
('Barcelona', 'ESP'), 
('Madrid', 'ESP');

INSERT INTO Users (username, country_code) VALUES 
('00000001', 'ESP'), 
('00000002', 'ESP'), 
('00000003', 'ITL'), 
('00000004', 'ITL');

INSERT INTO UsersCountries (username, city_name, country_code) 
VALUES 
('00000002', 'Madrid', 'ESP'), 
('00000004', 'Roma', 'ITL');
平心而论,大多数SQL编码人员不会厌恶使用
NULL
able列,而是更喜欢将所有用户的详细信息显示在一个表中。假设您的SQL产品(正确地)没有将
NULL
视为一个值(例如,MS SQL Server没有,但MS Access有),则以下内容将起作用,并与上述结构等效(即,尽管存在
NULL
可编辑列,但仍然贯穿引用整数):


+1在这一点上,有时正常化会造成比必要时更大的痛苦。我想补充的唯一一点是,您可以而且可能应该进行验证,以确保该城市位于选定的国家/地区。Marjan,非常感谢您的输入(我得到的越多,我对使用某个解决方案的感觉就越好)。你对学习这类东西有什么建议吗?我是应该选一本关于数据库设计的书,还是有好的网络资源?关于这个话题的问题是,我寻找这个问题的答案,但实际上只是空手而归。我担心我在数据库设计方面所做的所有决定都可能远远不够完美…@Geoff,对,谢谢你支持我的回答。还有+1提醒我确认这个城市(我显然是在计划它,但我很容易忘记这些事情是随着Rails的敏捷性发展而来的)。@tjko:很抱歉,我没有推荐书名之类的东西。总的来说:不要拘泥于数据库设计,要高高在上,想想你正在建模的东西。如果它们是不同的概念,请将它们分开。除非有(经证实的)需要,否则不要进行优化。除此之外:多与经验丰富的人交谈(像这里这样),了解他们的观点,即使他们相互矛盾,你也会对赞成者和反对者有一种感觉。多谢大家的意见,OmniBus!谢谢你的回复。我将其标记为SQL,因为我认为精通SQL的人可能会对数据库设计提供很好的见解,但我可能错误地认为,对不起(我是新来的)。无论如何,谢谢你的回答,我能读一点,但我必须说它的水平有点太低了,没有太多的设计问题,我要说的是。重点是,这些设计没有重复!当然,所有三个/四个表都会显示国家代码,但每个表都是维护数据完整性所必需的。你不能从一个城市中“推断”一个国家(例如,它是巴黎、德克萨斯还是巴黎、法国?),因此使用复合键。你确定一个城市一定在一个国家吗?反例可能是柏林(过去糟糕的日子)和耶路撒冷(现在)。我想还有其他的。很好,我不知道我该如何处理这些异常。。。
CREATE TABLE Countries 
(
 country_code CHAR(3) NOT NULL UNIQUE
);

CREATE TABLE Cities 
(
 city_name VARCHAR(20) NOT NULL, 
 country_code CHAR(3) NOT NULL 
    REFERENCES Countries (country_code), 
 UNIQUE (country_code, city_name)
);

CREATE TABLE Users
(
 username CHAR(8) NOT NULL UNIQUE, 
 country_code CHAR(3) NOT NULL, 
 UNIQUE (country_code, username)
);

CREATE TABLE UsersCountries
(
 username CHAR(8) NOT NULL UNIQUE, 
 country_code CHAR(3) NOT NULL, 
 FOREIGN KEY (country_code, username)
    REFERENCES Users (country_code, username), 
 city_name VARCHAR(20) NOT NULL, 
 FOREIGN KEY (country_code, city_name)
    REFERENCES Cities (country_code, city_name)
);
INSERT INTO Countries (country_code) VALUES 
('ITL'), 
('ESP');

INSERT INTO Cities (city_name, country_code) 
VALUES 
('Roma', 'ITL'), 
('Naples', 'ITL'), 
('Barcelona', 'ESP'), 
('Madrid', 'ESP');

INSERT INTO Users (username, country_code) VALUES 
('00000001', 'ESP'), 
('00000002', 'ESP'), 
('00000003', 'ITL'), 
('00000004', 'ITL');

INSERT INTO UsersCountries (username, city_name, country_code) 
VALUES 
('00000002', 'Madrid', 'ESP'), 
('00000004', 'Roma', 'ITL');
CREATE TABLE Users
(
 username CHAR(8) NOT NULL UNIQUE, 
 city_name VARCHAR(20), 
 country_code CHAR(3) NOT NULL
    REFERENCES Countries (country_code), 
 FOREIGN KEY (country_code, city_name)
    REFERENCES Cities (country_code, city_name)
);

INSERT INTO Users (username, city_name, country_code) VALUES 
('00000001', NULL, 'ESP'), 
('00000002', 'Madrid', 'ESP'), 
('00000003', NULL, 'ITL'), 
('00000004', 'Roma', 'ITL');