2010-06-23 140 views
2

我想这个查询是一个基本的,我应该知道更多关于SQL,但没有做很多与连接,但我认为这是解决方案。如何合并2个SQL表中的行而不重复行?

我所拥有的是一张人们的桌子和他们所拥有的工作角色表。一个人可以有多个工作,我希望有一组结果,每个人包含他们的详细信息和工作角色。

两个示例表(people和job_roles)在下面,因此您可以更容易地理解问题。

人民

 
id | name | email_address | phone_number 
1 | paul | [email protected] | 123456 
2 | bob | [email protected] | 567891 
3 | bart | [email protected] | 987561 

job_roles

 
id | person_id |  job_title | department 
    1 |  1  |  secretary | hr 
    2 |  1  |  assistant | media 
    3 |  2  |  manager | IT 
    4 |  3  | finance clerk | finance 
    4 |  3  |  manager | IT 

让我可以输出的每个人,像这样的

 
Name: paul 
Email Address: [email protected] 
Phone: 123456 
Job Roles: 
Secretary for HR department 
Assistant for media department 
_______ 
Name: bob 
Email address: [email protected] 
Phone: 567891 
Job roles: 
Manager for IT department 

自己的角色所以,我怎么会得到每个人的信息(从人员表格)和他们的工作细节(从job_roles表格)输出到上面的例子。我想这可能是某种将他们的工作和相关部门合并成一个可以分割输出的工作列的方式,但也许有更好的方法,sql会是什么样子?

感谢

保罗

PS这将是一个MySQL数据库,如果有什么差别

回答

2

RE:

我希望SQL可以做聪明事 ,并很好地加入行一起 所以我基本上是有工作 列在它是人的就业机会。

你可以得到相当接近与

SELECT p.id, p.name, p.email_address, p.phone_number, 
group_concat(concat(job_title, ' for ', department, ' department') SEPARATOR '\n') AS JobRoles 
FROM People AS p 
    INNER JOIN job_roles AS r ON p.id = r.person_id 
GROUP BY p.id, p.name, p.email_address, p.phone_number 
ORDER BY p.name; 
+1

感谢这是我最终使用的,它运作良好。 – AdrenalineJunky 2010-07-22 08:21:51

+0

这是非常聪明和方便的知道,但我仍然喜欢在PHP中进行正常的连接和格式化数据。如果您想要更改格式(例如,在作业角色之间添加
),您必须修改SQL查询。 GROUP_CONCAT删除了数据库逻辑和表示的分离。这也使得单元测试更加困难。 – dave1010 2010-07-27 12:20:40

3

它看起来像一个直接的连接:

SELECT p.*, j.* 
    FROM People AS p INNER JOIN Roles AS r ON p.id = r.person_id 
ORDER BY p.name; 

的的其余部分工作正在格式化;这最好由报告包完成。


感谢您的快速反应,这似乎是一个良好的开端,但你得到的多行每人像(你必须想象这是因为你似乎并不能够在注释格式的表):

id | Name | email_address | phone_number | job_role | department 
1 | paul | [email protected] | 123456  | secretary | HR 
1 | paul | [email protected] | 123456  | assistant | media 
2 | bob | [email protected] | 567891  | manager | IT 

我想每人一排最好在它所有的工作角色,如果这是可能的吗?

它取决于您的DBMS,但大多数可用的不支持RVAs - 关系值属性。你想是有结果的像与用户相关联的表中的职位和部门的部分:

+----+------+------------------+--------------+------------------------+ 
| id | Name | email_address | phone_number | dept_role   | 
+----+------+------------------+--------------+------------------------+ 
| |  |     |    | +--------------------+ | 
| |  |     |    | | job_role | dept | | 
| 1 | paul | [email protected] | 123456  | | secretary | HR | | 
| |  |     |    | | assistant | media | | 
| |  |     |    | +--------------------+ | 
+----+------+------------------+--------------+------------------------+ 
| |  |     |    | +--------------------+ | 
| |  |     |    | | job_role | dept | | 
| 2 | bob | [email protected] | 567891  | | manager | IT | | 
| |  |     |    | +--------------------+ | 
+----+------+------------------+--------------+------------------------+ 

这准确地表示您想要的信息,但通常不是一种选择。

因此,接下来会发生什么取决于您的报告生成工具。使用我最熟悉的(Informix ACE,可从IBM获得用于Informix DBMS的Informix SQL的一部分),您只需确保数据已排序,然后打印名称,电子邮件地址和电话号码在报告的'BEFORE GROUP of ID'部分中,在'ON EVERY ROW'部分中,您将只处理(打印)角色和部门信息。

将报告格式与数据检索操作分开通常是一个好主意;这是一个必要的例子,除非你的数据库管理系统有不寻常的功能来帮助选择数据的格式。


哦,亲爱的,听起来很复杂,不是我可以在一个PHP页面MySQL数据库上轻松地运行?

RVA的东西 - 你是对的,那不适用于MySQL和PHP。

另一方面,有数百万的报告(意味着格式化为向用户呈现的查询的结果)大致这样做。他们的技术术语是'Control-Break Report',但基本思想并不难。

您保留上次处理的'id'号码的记录 - 您可以将其初始化为-1或0. 当当前记录具有与先前号码不同的id号码时,则您有一个新用户,您需要为新用户启动一组新的输出行并打印名称,电子邮件地址和电话号码(并更改最后处理的ID号)。当前记录具有相同的ID号码时,您所做的只是处理工作角色和部门信息(而不是名称,电子邮件地址和电话号码)。当ID号码改变时发生'break'。在单一控制水平的情况下,这并不难;如果你有4个或5个级别,你必须做更多的工作,这就是为什么有报告包来处理它。

所以,这并不难 - 它只是需要一点小心。

+0

+1:打败我,所以我只需添加(此链接关于直观地表示JOINs)[http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html] – 2010-06-23 20:06:32

+0

感谢您的快速响应,这似乎是一个好开始,但你会得到每个人喜欢多行(你必须想象这是一张桌子,因为你似乎无法在评论中格式化): ID |名称| email_address | phone_number | job_role |部门 1 | paul | [email protected] | 123456 |秘书| HR 1 | paul | [email protected] | 123456 |助理|媒体 2 | bob | [email protected] | 567891 |经理| IT 如果可能的话,我希望每个人都有理想的一行工作角色吗? – AdrenalineJunky 2010-06-23 20:20:32

+0

哦,亲爱的,听起来很复杂,而不是我可以轻松地在PHP页面的mySQL数据库上运行? – AdrenalineJunky 2010-06-23 21:12:03

0

这样做你想要的方式将意味着结果集数组可能会有无限的列,这将是非常混乱。例如,您可以将作业表加入10次,并获得job1,job2,... job10。

我会做单一连接,然后使用PHP来检查名称ID是否从1行到下一个相同。

+0

谢谢,这是我刚才的结论,但希望SQL能够聪明地做些事情,并且将这些行很好地结合在一起,所以我基本上已经有了一个工作列,并且有人在其中工作。 – AdrenalineJunky 2010-06-23 21:13:40

0

的一种方式可能是左外连接的表,然后向上它们加载到一个数组使用

$people_array =array(); 
while($row1=mysql_fetch_assoc($extract1)){ 
$people_array[] = $row1; 
} 

,然后遍历使用

for ($x=0;$x<=sizeof($people_array;) 
    { 
echo $people_array[$x][id]; 
echo $people_array[$x][name]; 

for($y=0;$y<=$number_of_roles;$y++) 
{ 
echo $people_array[$x][email_address]; 
echo $people_array[$x][phone_number]; 
    $x++; 
} 
    } 

您可能需要玩查询一点和循环,但它应该做一般你想要的。对于上面的工作,每个人都必须具有相同数量的角色,但是您可以填写表格中的空白。

+0

好主意,但组concat似乎是一个更干净的解决方案。 – AdrenalineJunky 2010-07-22 08:22:37