【问题标题】:SQL JOIN Multiplies Result Set - Cartesian ProductSQL JOIN 乘以结果集 - 笛卡尔积
【发布时间】:2016-05-28 02:33:43
【问题描述】:

我有一个基表,我想再加入 2 个表来获取我需要的所有数据。运行查询时,我得到一个笛卡尔积,因为其中 2 个表(主表和我要加入的另一个表)正在通过 non-unique 键加入。

这是一个例子:

发票 (i)

id    order_id       name             comment
-----------------------------------------------------------------
1     500            Males            Mice
2     500            Females          Mice
3     500            Courier Fee      Within City

订单(o)

id    order_number
------------------------------
500   AN5246516264

订购商品 (oi)

id    order_id       strain_id    species_id      comments
-----------------------------------------------------------------
1100  500            858          9876            Mice
1101  500            858          9876            Mice
1102  500            NULL         NULL            Within City

使用上面定义的表,这是我的查询:

查询

SELECT
    i.name, i.comment,
    o.order_number,
    oi.strain_id, oi.species_id
FROM invoice i
LEFT JOIN order o
    ON i.order_id = o.id
LEFT JOIN order_items oi
    ON o.id = oi.order_id

运行查询后,我得到一个笛卡尔积,如下所示(不一定按顺序):

name         comment        order_number     strain_id    species_id
-----------------------------------------------------------------------
Males        Mice           AN5246516264     858          9876 ---> I want this row
Males        Mice           AN5246516264     858          9876
Males        Within City    AN5246516264     NULL         NULL
Females      Mice           AN5246516264     858          9876
Females      Mice           AN5246516264     858          9876 ---> I want this row
Females      Within City    AN5246516264     NULL         NULL
Courier Fee  Mice           AN5246516264     858          9876
Courier Fee  Mice           AN5246516264     858          9876
Courier Fee  Within City    AN5246516264     NULL         NULL ---> I want this row

我了解这里发生了什么,我知道为什么它会导致笛卡尔积,但我不知道如何解决我的问题。

我只想将order_numberstrain_idspecies_id 附加到Invoice (i) 表中。

是的,表格结构的构建方式有些奇怪。我确实相信数据库设计师在制作表格时已经陶醉了,但这不是我现在可以改变的。

有什么建议吗?

编辑

我查看了所有 3 个表,但找不到任何其他列可以加入它们。我留下了order_id

【问题讨论】:

  • 问题是,“如何将发票项目链接到订单项目”。理论上问这个问题,不是这里的数据库问题。实际上,没有特定的链接,即使 cmets 也不是唯一的。我能看到的唯一可能性是您假设两个表中的项目顺序相同(在这种情况下,您可以使用 orderby 尝试加入它们),或者您必须忽略发票或订单项目表,以便您不要'没有得到乘法问题。
  • 您想要保留的行有什么独特之处?
  • 在 @Lukos 的基础上,您可以在 Order items 表上的 order id 上排列行,并将该 rank id 连接到 invoice 表的 id。您必须检查将数据添加到这些表的过程,以确保它们按顺序插入,与 Order Items 表相同。
  • @Lukos 是的,这是个问题,因为我不知道为什么要这样构建。但我只能看到order_id 是我可以用来加入它们的唯一列。我确实需要来自所有 3 个表的数据,所以忽略其中 2 个表是不可行的。至于顺序,我不想依赖它,因为其他记录的格式可能不同。
  • 当您查看该结果列表时,您如何知道在哪些结果旁边放置“---> 我想要这一行”?

标签: sql oracle join cartesian-product


【解决方案1】:

您可以首先使用函数row_number() 对表ioi 中的行进行编号,然后将其用作连接条件的一部分:

with i as  (select row_number() over (partition by order_id order by id) rn, i.*  
              from invoice i),
     oi as (select row_number() over (partition by order_id order by id) rn, oi.* 
              from order_items oi)
select i.name, i.comments, o.order_number, oi.strain_id, oi.species_id
  from i left join orders o on i.order_id = o.id
  left join oi on oi.order_id = o.id and oi.rn = i.rn

测试数据和输出:

create table invoice (id number(4), order_id number(4), 
  name varchar2(15), comments varchar2(20));
insert into invoice values (1, 500, 'Males', 'Mice');
insert into invoice values (2, 500, 'Females' ,'Mice');
insert into invoice values (3, 500, 'Courier Fee', 'Within City');
--
create table orders (id number(4), order_number varchar2(15));
insert into orders values (500, 'AN5246516264');
--
create table order_items(id number(5), order_id number(4), 
  strain_id number(5), species_id number(5), comments varchar2(20));
insert into order_items values(1100, 500, 858,  9876, 'Mice');
insert into order_items values(1101, 500, 858,  9876, 'Mice');
insert into order_items values(1102, 500, NULL, NULL, 'Within City');

输出:

NAME            COMMENTS             ORDER_NUMBER    STRAIN_ID SPECIES_ID
--------------- -------------------- --------------- --------- ----------
Males           Mice                 AN5246516264          858       9876
Females         Mice                 AN5246516264          858       9876
Courier Fee     Within City          AN5246516264              

【讨论】:

  • 我可以看到这个工作if and only if 项目是有序的。如果不是,那么我将得到一个错误的结果集。
  • 好的,我试过了,它有效,所以我赞成它。但我不能接受它作为答案,因为我不能确定两个表中的所有行都处于相同的顺序。
  • 我现在在实际的实时数据上运行了这个,由于排序,我得到了一些奇怪的结果。行数是正确的。所以,是的,这没有用,但这是一个很好的尝试,我会在一个订购不是问题的完美世界中选择这个解决方案。
  • 我稍微修改了查询,我能够解决问题。它现在按我想要的方式工作。而不是order by id,我使用order by rownum。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多