2014-11-17 29 views
0

我有一个标准的用户表。现在每个用户都可以在他的个人资料中添加未知数量的语言。为每个用户存储语言的最佳方式是什么?我只想询问一次以获取用户及其所有相应的语言。什么是最好的设计?如何为每个用户存储可变数量的语言?

例子:

User 
==== 

id name  
---------- 
99 peter 


Languages 
========= 

id userid lang 
-------------------- 
44 99  en 
45 99  fr 
+0

您需要第三张表用户和语言'new_table(uderid,languageid)'之间的关系并保留'languages(id,lang)' –

+0

用户和语言表可以与'id'和'userid'列关联在上面的设计中,不需要第三张表。我认为这很好。 –

+0

是的,我会这样做,但这不是我要求的点 – Patrick

回答

1

这是一个多对多的关系(一个用户可以有许多语言,反之亦然),所以正常化DB你应该做包含两个外键的新表(称之为user_x_languages ):

user_x_languages 
================ 
user_id lang_id 
99   44 
99   45 

你需要从你的语言表中删除用户ID列

查询应再使用连接

select name lang from user u 
join user_x_languages x on u.id = x.user_id 
join languages l on x.lang_id = l.id 
where u.id = 99; 

这会为用户所拥有的每种语言输出一行,但它会重复每行的用户名。

你想看看DB正常化,一个非常漂亮的非技术性的文章是这样的:A Simple Guide to Five Normal Forms in Relational Database Theory

以下this线程的建议有关返回一行,程序会像(我可能已经改变了表和列名从原来的一点点):

delimiter // 

Create function languages (p_user varchar(30)) 
returns text 
begin 
    DECLARE ret_val TEXT; 
    select GROUP_CONCAT(lang) into ret_val 
    from Users u 
    join user_x_lang x on u.user_id = x.user_id 
    join Lang l on x.lang_id = l.lang_id 
    where u.name = p_user; 
    return ret_val; 
end// 

delimiter ; 

现在的选择应该是(对所有用户):

select name, languages(name) from users; 
+0

谢谢,那么最好的做法是查询用户和他的所有语言呢?重复用户名等似乎不是最好的? – Patrick

+0

由于您使用特定的用户名进行查询,因此可以省略select语句中的名称。 在多个用户的情况下,你可以使用一个函数来查询每个用户的数据库,并将它们作为文本返回 – Maor

+0

是的,但我会有其他用户的列,如电子邮件,照片等。我希望所有的用户数据一次和添加的语言 – Patrick

1

您可以创建一个多对多的关系表。就像这样:

表 “用户”

user_id | name 
99  peter 
100  tim 

表 “语言”

language_id | language 
44   en 
45   fr 

表 “User_to_language”

User_id | Language_id 
99  45 
100  45 
100  46 

或者,如果你需要大量的用户属性在将来,您可能会使用类似于: 表User_attributes

user_id | attribute | value 
46  'lang'  'en' 

而且,这可能对您有用:Database normalization

+0

你能写一个查询来获取用户加入他的语言的用户数据吗? – Patrick

+0

选择u.name,l.language 从用户ü 加入User_to_language UTL 上utl.User_id = u.User_id 加入语言升 上l.Language_id = utl.Language_id 其中u.name = '添'; –

+0

这也将返回一个表与每种语言 - 正确 - 但在每一行的用户数据也被添加。这是最佳做法吗? – Patrick

1

正常化是用来保存磁盘空间,即一个好的规范化的数据库需要较少的空间比非标准化的,但是你付出的代价是性能。请记住更多的标准化=更多的联合=更多的处理开销。 在我看来,(使用两个表)你的设计是好的,你可以很容易地检索数据单个连接:

select * from Usrs u join Languages l on u.id = l.usrid 

now some sample queries which will come in application code 
--select those users who speak 'en' then 

select * from Usrs u join Languages l on u.id = l.usrid 
where l.lang = 'en' 

--peter speaks which languages 
select * from Usrs u join Languages l on u.id = l.usrid 
where u.name = 'peter' 

尝试用一个标准化的数据基础相同,你会发现,你需要所有三个表获得所需的数据。

相关问题