如何处理使用PHP从SQL查询返回的树结构?

时间:2011-01-31 12:50:38

标签: php mysql sqlite

这是一个“理论上的”问题。

我无法定义问题所以请耐心等待。

当您在数据库中有多个相关表时,例如一个包含“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的解决方案是最合适的。

4 个答案:

答案 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,最好的解决方案是使用工厂模式来正确管理映射。