这是一个“理论上的”问题。
我无法定义问题所以请耐心等待。
当您在数据库中有多个相关表时,例如一个包含“users”的表和一个包含“phones”的表
“电话”和“用户”都有一个名为“user_id”的列
select user_id,name,phone from users left outer join phones on phones.user_id = users.user_id;
查询将为我提供所有用户的行,无论他们是否有电话。
如果用户有多部电话,他的名字将按预期返回2行。
columns=>|user_id|name|phone|
row0 = > | 0 |fred|NULL|
row1 = > | 1 |paul|tlf1|
row2 = > | 1 |paul|tlf2|
上述案例中的“paul”这个名称是必要的副本,在RDMS的眼中根本不重复! 然后它将由一些服务器端脚本语言处理,例如php。
如何在真实网站或应用程序中实际处理这些“必要的重复”? 如何,行如何“映射”到一些可用的对象模型中。
P.S。如果您决定发布示例,请尽可能将它们发布到php,mysql,sqlite。
修改
感谢您提供答案,每个答案都以不同的方式解释了问题,因此它本身就是不同的和正确的。
我得出的结论是,如果往返费用昂贵,这将是雅各布·尼尔森 - 埃勒的解决方案的最佳方式,这符合理论问题。
如果往返他们便宜,我会为9000建议单独选择手机和用户,如果我需要为每个用户显示一部手机,我会给手机一个主列并与用户联系选择像奥利琼斯正确建议。
即使对于现实生活中的应用程序我使用9000的答案,我认为对于这个不切实际的问题,Jakob Nilsson-Ehle的解决方案是最合适的。
答案 0 :(得分:1)
您的数据模型本身允许用户拥有0个,1个或更多手机。
你可以让你的数据库通过使用令人讨厌的黑客来为每个用户返回0或1个电话项目,例如选择数字最小的电话号码。 (MIN(电话)... GROUP BY用户)。但是在数字上比较电话号码是没有意义的。
您的歧义问题(多个电话号码中的哪一个)指出数据模型设计中存在问题。如果您愿意,请查看一些常见的电话目录应用程序。手机上的快速拨号应用就是一个很好的例子。大多数情况下,他们提供了输入多个电话号码的方法,但他们总是拥有主要电话号码的概念。
如果您在电话表中添加一列表示号码优先级,并将其作为主要(唯一)键的一部分,并声明优先级= 1表示用户的主号码,则您的应用不会再出现此模糊问题
答案 1 :(得分:1)
您无法轻松从RDBMS获取树结构,只能获取表结构。你想要一棵树:[(user1, (phone1, phone2)), (user2, (phone2, phone3))...]
。但是,您可以针对不同的目标进行优化。
往返比发送额外信息更昂贵:使用您当前的解决方案。它多次获取用户名,但每个电话簿只有一次往返。如果您的负担过重的MySQL主机距离1000英里,那么可能会有意义。
发送额外信息比往返更昂贵,或者您想要更清晰:正如@ martinho-fernandes建议的那样,只能通过手机获取用户ID,然后在另一个查询中获取用户详细信息。除非您的整个用户详细信息是一个简短的用户名,否则我会坚持使用此方法。使用SQLite,为了清楚起见,我始终坚持使用它。
答案 2 :(得分:1)
在这种情况下我可能会在PHP中做的事情是在PHP数组中使用userId然后使用它来持续更新用户
一个非常简单的例子是
$result = mysql_query('select user_id,name,phone from users left outer join phones on phones.user_id = users.user_id;'); $users = Array(); while($row = mysql_fetch_assoc($result)) { $uid =$row['user_id']; if(!array_key_exists($uid, $users)) { $users[$uid] = Array('name' => $row['name'], 'phones' => Array()); } $users[$uid]['phones'][] = $row['phone']; }
当然,根据您的编程风格和用户数据的复杂性,您可以定义一个User类或其他内容并填充数据,但这基本上就是我会这样做的。
答案 3 :(得分:1)
声音就像您将对象数据模型与关系数据模型混淆一样 - 了解它们differ in general的方式,以及应用程序的细节对于在关系数据库之上编写OO代码至关重要。
琐碎的ORM不是解决方案。
有一些ORM映射技术,例如hibernate - 但是这些技术不能很好地扩展。 IME,最好的解决方案是使用工厂模式来正确管理映射。