sql - 使用一个 JOIN 次数越多,列越多

标签 sql join

我有如下四张表(还有很多,其实这道题我省略了不重要的):

enter image description here

使用联结表,一个产品最多可以关联 5 个组。我需要JOIN 表格并将所有 5 个组和 5 个区域以及一个关联产品打印为 11 列。

预期结果(例如):

+---------+---------+---------+---------+---------+---------+
| Product | Group 1 | Group 2 | Group 3 | Group 4 | Group 5 |
+---------+---------+---------+---------+---------+---------|
|    1    |    2    |    1    |   NULL  |   NULL  |   NULL  |
+---------+---------+---------+---------+---------+---------+

          +---------+---------+---------+---------+---------+
          | Area 1  | Area 2  | Area 3  | Area 4  | Area 5  |
          +---------+---------+---------+---------+---------|
          |    5    |    8    |   NULL  |   NULL  |   NULL  |
          +---------+---------+---------+---------+---------+

我有以下 SQL 查询: `

Select p.id, a1.area_id as 'Area 1', a2.area_id as 'Area 2', a3.area_id as 'Area 3', a4.area_id as 'Area 4', a5.area_id as 'Area 5', g1.group_id as 'Group 1', g2.group_id as 'Group 2', g3.group_id as 'Group 3', g4.group_id as 'Group 4', g5.group_id as 'Group 5'
From Product p
Inner Join group_product_junction j on p.product_id = j.product_id
Inner Join Group g1 on j.group_id = g1.group_id
Inner Join Group g2 on j.group_id = g2.group_id
Inner Join Group g3 on j.group_id = g3.group_id
Inner Join Group g4 on j.group_id = g4.group_id
Inner Join Group g5 on j.group_id = g5.group_id
Inner Join Area a1 a on g1.area_id = a1.area_id
Inner Join Area a2 a on g2.area_id = a2.area_id
Inner Join Area a3 a on g3.area_id = a3.area_id
Inner Join Area a4 a on g4.area_id = a4.area_id
Inner Join Area a5 a on g5.area_id = a5.area_id

`

但这为我提供了所有列的相同值。我想我缺少一个 WHERE 子句或其他东西,但我就是想不出它应该是什么样子。

最佳答案

为了实现您的要求,您必须在链接到给定产品的组中创建订单 的概念。这是因为您最终将按特定顺序选择最多五个组(和区域)(即 1 组、2 组、3 组等),对于给定的产品。

可以使用 order by 子句实现整个结果集的排序,但这在这里还不够,因为我们需要独立地为每个产品排序。这就是分区函数存在的原因;允许对结果集的子组进行操作,而无需在此过程中将整个组聚合到一个记录中(这是 group by 所做的)。

因此,我们可以做的是将每个产品记录与其所有组(正如您所指出的,每个产品的数量不能超过五个)连接起来,然后运行分区函数 row_number()按产品划分。这将允许我们创建一个新列,该列将在该产品的组集中用不同的数字标记每个产品的每个组。然后,我们将能够 left join 标记的中间表五次,分别过滤标签 1、2、3、4 和 5,从而使每个组都进入自己的连接。然后通过组表和区域表遍历表链接来获取我们构建所需结果集所需的所有信息是一件简单的事情。

create table FArea (area_id int primary key);
create table FGroup (group_id int primary key, area_id int references FArea(area_id));
create table FProduct (product_id int primary key);
create table Fgroup_product_junction (group_id int references FGroup(group_id), product_id int references FProduct(product_id));

-- product 1
insert into FProduct (product_id) values (1);
insert into FArea (area_id) values (1), (2), (3), (4), (5);
insert into FGroup (group_id,area_id) values (1,1), (2,2), (3,3), (4,4), (5,5);
insert into Fgroup_product_junction (group_id,product_id) values (1,1), (2,1), (3,1), (4,1), (5,1);

-- product 2
insert into FProduct (product_id) values (2);
insert into FArea (area_id) values (6), (7), (8);
insert into FGroup (group_id,area_id) values (6,6), (7,7), (8,8);
insert into Fgroup_product_junction (group_id,product_id) values (6,2), (7,2), (8,2);

select * from FArea;
select * from FGroup;
select * from FProduct;
select * from Fgroup_product_junction;

with t_pg as (
    select
        p.product_id,
        j.group_id,
        row_number() over (partition by p.product_id order by j.group_id) num
    from
        FProduct p
        inner join Fgroup_product_junction j on j.product_id=p.product_id
)
select
    p.product_id "Product",
    g1.group_id "Group 1",
    g2.group_id "Group 2",
    g3.group_id "Group 3",
    g4.group_id "Group 4",
    g5.group_id "Group 5",
    a1.area_id "Area 1",
    a2.area_id "Area 2",
    a3.area_id "Area 3",
    a4.area_id "Area 4",
    a5.area_id "Area 5"
from
    FProduct p
    left join t_pg j1 on j1.product_id=p.product_id and j1.num=1 left join FGroup g1 on g1.group_id=j1.group_id left join FArea a1 on a1.area_id=g1.area_id
    left join t_pg j2 on j2.product_id=p.product_id and j2.num=2 left join FGroup g2 on g2.group_id=j2.group_id left join FArea a2 on a2.area_id=g2.area_id
    left join t_pg j3 on j3.product_id=p.product_id and j3.num=3 left join FGroup g3 on g3.group_id=j3.group_id left join FArea a3 on a3.area_id=g3.area_id
    left join t_pg j4 on j4.product_id=p.product_id and j4.num=4 left join FGroup g4 on g4.group_id=j4.group_id left join FArea a4 on a4.area_id=g4.area_id
    left join t_pg j5 on j5.product_id=p.product_id and j5.num=5 left join FGroup g5 on g5.group_id=j5.group_id left join FArea a5 on a5.area_id=g5.area_id
;

results

关于sql - 使用一个 JOIN 次数越多,列越多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31851579/

相关文章:

mysql - 使用mysql根据年龄过滤成员

jquery - 带有 sql server 数据的 Highcharts

php - 有没有更好的方法在 mysql 和 PHP 中查询这个

sql - 如何将 3 个 SQL 查询合并为 1 个?

mysql - ORDER BY 在子查询连接中被忽略?

mysql 不返回正确的 json

java - 使用 JOIN 从单个 SQL 查询将汽车预订添加到汽车对象

excel - VBA 类型与 Join 函数不匹配错误

php - 使用 mysql 选择前 10 个最近的事情

MySQL Union 结果是一列而不是行