如何合并 2 个 SQL 表中的行而不重复行?

发布于 2024-09-06 22:38:36 字数 1788 浏览 6 评论 0原文

我想这个查询有点基础,我应该更多地了解 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 会是什么样子?

谢谢

Paul

PS 如果这有什么区别的话,它会是一个 mySQL 数据库

I guess this query is a little basic and I should know more about SQL but haven't done much with joins yet which I guess is the solution here.

What I have is a table of people and a table of job roles they hold. A person can have multiple jobs and I wish to have one set of results with a row per person containing their details and their job roles.

Two example tables (people and job_roles) are below so you can understand the question easier.

People

 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

so that I can output each person and their roles like such

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

So how would I get each persons information (from the people table) along with their job details (from the job_roles table) to output like the example above. I guess it would be some kind of way of merging their jobs and their relevant departments into a jobs column that can be split up for output, but maybe there is a better way and what would the sql look like?

Thanks

Paul

PS it would be a mySQL database if that makes any difference

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

佼人 2024-09-13 22:38:36

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

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,但大多数可用的 DBMS 不支持 RVA(关系值属性)。您想要的是结果中包含工作角色和部门部分,就像与用户关联的表一样:

+----+------+------------------+--------------+------------------------+
| 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,Informix SQL 的一部分,可从 IBM 获得,与 Informix DBMS 一起使用),您只需确保数据已排序,然后打印姓名、电子邮件地址和电话号码在报告的“BEFORE GROUP OF id”部分和“ON EVERY ROW”部分中,您将仅处理(打印)角色和部门信息。

将报告格式化与数据检索操作分开通常是一个好主意;这是一个必要的示例,除非您的 DBMS 具有帮助格式化所选数据的特殊功能。


天哪,这听起来非常复杂,我无法在 PHP 页面的 mySQL 数据库上轻松运行?

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

另一方面,有数百万个报告(指的是经过格式化以呈现给用户的查询结果)大致可以完成此操作。它们的技术术语是“Control-Break Report”,但是基本思想并不难。

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

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

It looks like a straight-forward join:

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

The remainder of the work is formatting; that's best done by a report package.


Thanks for the quick response, that seems a good start but you get multiple rows per person like (you have to imagine this is a table as you don't seem to be able to format in comments):

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

I would like one row per person ideally with all their job roles in it if that's possible?

It depends on your DBMS, but most available ones do not support RVAs - relation-valued attributes. What you'd like is to have the job role and department part of the result like a table associated with the user:

+----+------+------------------+--------------+------------------------+
| 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    | |
|    |      |                  |              | +--------------------+ |
+----+------+------------------+--------------+------------------------+

This accurately represents the information you want, but is not usually an option.

So, what happens next depends on your report generation tool. Using the one I'm most familiar with, (Informix ACE, part of Informix SQL, available from IBM for use with the Informix DBMSs), you would simply ensure that the data is sorted and then print the name, email address and phone number in the 'BEFORE GROUP OF id' section of the report, and in the 'ON EVERY ROW' section you would process (print) just the role and department information.

It is often a good idea to separate the report formatting from the data retrieval operations; this is an example of where it is necessary unless your DBMS has unusual features to help with the formatting of selected data.


Oh dear that sounds very complicated and not something I could run easily on a mySQL database in a PHP page?

The RVA stuff - you're right, that is not for MySQL and PHP.

On the other hand, there are millions of reports (meaning results from queries that are formatted for presentation to a user) that do roughly this. The technical term for them is 'Control-Break Report', but the basic idea is not hard.

You keep a record of the 'id' number you last processed - you can initialize that to -1 or 0.
When the current record has a different id number from the previous number, then you have a new user and you need to start a new set of output lines for the new user and print the name, email address and phone number (and change the last processed id number). When the current record has the same id number, then all you do is process the job role and department information (not the name, email address and phone number). The 'break' occurs when the id number changes. With a single level of control-break, it is not hard; if you have 4 or 5 levels, you have to do more work, and that's why there are reporting packages to handle it.

So, it is not hard - it just requires a little care.

叫思念不要吵 2024-09-13 22:38:36

关于:

我希望 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;

RE:

I was hoping SQL could do something
clever and join the rows together
nicely so I had essentially a jobs
column with that persons jobs in it.

You can get fairly close with

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;
难得心□动 2024-09-13 22:38:36

按照您想要的方式进行操作将意味着结果集数组可能具有无限列,这将非常混乱。例如,您可以左连接 jobs 表 10 次并获取 job1、job2、.. job10。

我会执行一次连接,然后使用 PHP 检查第一行到下一行的名称 ID 是否相同。

Doing it the way you're wanting would mean the result set arrays could have infinite columns, which would be very messy. for example, you could left join the jobs table 10 times and get job1, job2, .. job10.

I would do a single join, then use PHP to check if the name ID is the same from 1 row to the next.

高速公鹿 2024-09-13 22:38:36

一种方法可能是左外连接表,然后使用将它们加载到数组中

$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++; 
} 
     } 

您可能需要稍微处理一下查询和循环,但它通常应该做您想要的事情。为了让它工作如上所述,每个人都必须拥有相同数量的角色,但您可以填写表格中的空白

One way might be to left outer join the tables and then load them up into an array using

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

and then loop through using

 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++; 
} 
     } 

You might have to play with the query a bit and the loops but it should do generally what you want.For it to work as above every person would have to have the same number of roles, but you may be able to fill in the blanks in your table

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文