Php 如何组合具有不同列的多个表的结果?

Php 如何组合具有不同列的多个表的结果?,php,mysql,join,union,Php,Mysql,Join,Union,我有几个表,它们有不同的列数和类型,还有一个共同的列 +--------+---------+------------+-------------+ | person | beardID | beardStyle | beardLength | +--------+---------+------------+-------------+ +--------+-------------+----------------+ | person | moustacheID | moustacheSt

我有几个表,它们有不同的列数和类型,还有一个共同的列

+--------+---------+------------+-------------+
| person | beardID | beardStyle | beardLength |
+--------+---------+------------+-------------+

+--------+-------------+----------------+
| person | moustacheID | moustacheStyle |
+--------+-------------+----------------+
我想获取与共享列的给定值匹配的所有结果。我可以使用多个select语句来执行此操作,如下所示:

SELECT * FROM beards WHERE person = "bob"
+--------+---------+------------+-------------+-------------+----------------+
| person | beardID | beardStyle | beardLength | moustacheID | moustacheStyle |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 1       | rasputin   | 1           |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 2       | samson     | 12          |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    |         |            |             | 1           | fu manchu      |
+--------+---------+------------+-------------+-------------+----------------+

但这需要多个mysql API调用,这似乎效率低下。我希望我可以使用UNIONALL在一个API调用中获得所有结果,但UNION要求表具有相同数量和相似类型的列。我可以编写一个SELECT语句,通过添加带有NULL值的列来手动填充每个表的结果,但是如果有更多的表包含更多的列,则很快就会变得无法管理

我正在寻找一个大致如下的结果集:

SELECT * FROM beards WHERE person = "bob"
+--------+---------+------------+-------------+-------------+----------------+
| person | beardID | beardStyle | beardLength | moustacheID | moustacheStyle |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 1       | rasputin   | 1           |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    | 2       | samson     | 12          |             |                |
+--------+---------+------------+-------------+-------------+----------------+
| bob    |         |            |             | 1           | fu manchu      |
+--------+---------+------------+-------------+-------------+----------------+
有没有一种快速且可维护的方法来实现这一点?还是最好对每个表运行单独的查询

澄清:

我不是在寻找笛卡尔积。我不想让胡子和胡子的每一个组合都排成一行,我想让每个胡子排成一行,每个胡子排成一行

因此,如果有3个相配的胡须和2个相配的胡子,我应该得到5排,而不是6排。

加入person

挑选 t1(星号),t2(星号) 从…起 胡须t1 内连接
t2上的胡须t2.person=t1.person

我对此很感兴趣,不确定你还需要添加什么,但它实现了目标

SELECT *
FROM   beards
       JOIN moustaches
         ON moustaches.person = beards.person
WHERE  person = "bob"  
create table beard (
person varchar(20)
,beardID int
,beardStyle varchar(20)
,beardLength int )

create table moustache(
person varchar(20)
,moustacheID int
,moustacheStyle varchar(20))


insert into beard 
select 'bob', 1, 'rasputin', 1
union select 'bob', 2, 'samson', 12

insert into moustache
select 'bob', 1, 'fu manchu'

declare @facialhair table (
person varchar(20)
,beardID int
,beardStyle varchar(20)
,beardLength int
,moustacheID int
,moustacheStyle varchar(20))

declare @i int
declare @name varchar(20)

set @name = 'bob'
set @i = (select COUNT(*) from beard where person = @name)
        + (select COUNT(*) from moustache where person = @name) 

print @i

while @i > 0
    begin 
        insert into @facialhair (person, beardID, beardStyle, beardLength)
        select person, beardID, beardStyle, beardLength
        from beard
        where person = @name
    set @i = @i-@@ROWCOUNT

        insert into @facialhair (person, moustacheID, moustacheStyle)
        select person, moustacheID, moustacheStyle
        from moustache
        where person = @name
    set @i = @i-@@ROWCOUNT
    end

select *
from @facialhair

这应该很好:

SELECT * FROM `beards` b LEFT OUTER JOIN `mustaches` ON (0) WHERE  person = "bob"
UNION ALL
SELECT * FROM `beards` b RIGHT OUTER JOIN `mustaches` ON (0) WHERE  person = "bob"
您不必自己处理这些列。左侧和右侧外部联接完成此工作。 不幸的是,mysql没有完全连接。这就是为什么你必须和工会这样做

SELECT * FROM `customer` b LEFT OUTER JOIN `charges` ON (0) LEFT OUTER JOIN `day` ON (0)
UNION
SELECT * FROM `customer` b RIGHT OUTER JOIN `charges` ON (0) LEFT OUTER JOIN `day` ON (0)
UNION
SELECT * FROM `customer` b LEFT OUTER JOIN `charges` ON (0) RIGHT OUTER JOIN `day` ON (0)

这是我做的本地测试

我认为查询每个表中的数据会更好


另一种可能性是将所有列中的数据连接成一个大字符串(您可以选择一些符号来分隔列的值),然后您应该能够使用union all子句来组合来自每个查询的结果,但随后您必须解析每一行。。数据类型将丢失。

您尝试过这个吗?内部联接从两个表中检索匹配记录的笛卡尔积。因此,胡须和胡子的每一种组合都会产生一个结果。根本不是问题中所描述的。@Robert:不,内部联接不会产生笛卡尔积。对不起,我不太理解联接。内部联接与采用笛卡尔积并根据联接条件进行过滤有什么区别?内部联接选择关系A中的所有记录以及关系B中具有共同值的所有记录,并输出包含这些行的结果集。笛卡尔积是创建一个结果集的结果,其中关系a和B中的所有行都毫无韵律或理由地挂在一起。也就是说,对于关系A中的每一行,关系B中的每一行都被添加到结果集中。那么,内部联接不就是这样做的吗?对于关系A中的每一行,将关系B中的每一行添加到结果集中,然后过滤该集,以便仅返回具有公共值的行。如果有差异,我仍然看不到。我希望为每个胡子检索一行,为每个胡子检索一行,而不是为每个胡子检索一行。主要缺点是计算开销和mysql对组_concat的字符串大小有限!看看我的解决方案。我认为这是最简单的方法。@ITroubs:我应该说,这是一个很好的解决方案,非常棒,很有魅力。因此,如果我理解正确,您使用的是左外部联接和右外部联接,而没有指定联接条件,以向每个表的结果中添加满null的列(以便结果集具有匹配的表),然后联合results.yep。连接只是为了使舒尔的结果包含胡须和胡须的所有列,通过使ON语句为false,它只返回胡须或胡须的所有行,具体取决于使用的连接。若要添加第三个表,我将在新表的每个选择中添加一个额外的外部连接ON(0),加上UNION ALL和一个新的select语句,外部以相同的方式将新表连接到这两个表。刚才看到你说的正是我所说的XDi在我的解决方案中添加了一个三表示例,而这可以在大多数数据库中通过
完全连接来完成,在MySQL中通过ITroubs的解决方案来完成,我严重怀疑这是否会带来显著的性能提升,而且您可能只是在创建一堆您的继任者不会感谢您的晦涩代码。在大多数情况下,清晰和精确的代码在非常低的百分比下超过了性能增益。