Oracle通过带有内部连接和返回n行的子查询的桥表选择查询?

Posted

技术标签:

【中文标题】Oracle通过带有内部连接和返回n行的子查询的桥表选择查询?【英文标题】:Oracle select query via bridge table with inner joins and subquery that returns n number of rows? 【发布时间】:2018-01-23 21:20:36 【问题描述】:

我开发了一个遵循星型模式的数据仓库。在这个模式中,我有多个维度表连接到我的事实表。但是,我在这些维度之一和事实表之间有一个桥接表。

即我的仓库架构示例

产品

Fact table contains: ProductGroup_SK...
ProductGroup table contains: ProductGroup_SK, Product_SK
Product table contains: Product_SK, product_fields...

我将使用 Oracle Data Miner 对我的数据仓库进行分析,并且一直在尝试根据连接ProductGroup 桥接表的事实表。

到目前为止,我已经能够成功加入并返回一行,但这仅适用于 productGroup 中只有两个产品的情况。此外,如果组中仅存在一种产品,则此查询将返回相同产品两次,因为我在查询本身中使用 MIN 和 MAX 指定了两个联接。

Select * from Fact f
join Product p ON p.Product_SK = (SELECT MIN(Product_SK) FROM ProductGroup pg WHERE pg.ProductGroup_SK = f.ProductGroup_SK)
join Product p ON p.Product_SK = (SELECT MAX(Product_SK) FROM ProductGroup pg WHERE pg.ProductGroup_SK = f.ProductGroup_SK);

我读到这里应该使用 PIVOT 查询,但我不需要执行任何聚合,并且每个 productGroup 中的行数对于事实表中的每一行不会相同,即某些组可能有只有 1 个产品,有些可能有 6 个。

基本上,我希望找到一种方法来获得与我上面所做的这种 hack 方式相同的结果,即结果而不是看起来像这样:

... ProductGroup_SK   Product_SK   Product_Name   Product_Category .. etc
           123            1           Apple           Fruit
           123            2           Banana          Fruit

应该是这样的:

... ProductGroup_SK   Product_SK   Product_Name   Product_Category   Product_SK_1   Product_Name_1   Product_Category_1 .. Product_SK_N   Product_Name_N   Product_Category_N
           123            1           Apple           Fruit                 2           Banana          Fruit               ...........      ..........      ..........

我在上面演示的查询产生了这个期望的结果,但正如您所见,它不是好的代码,并且对于包含少于或多于两个产品的 productGroups 是不切实际的。

任何建议都将不胜感激,我一直在尝试弄清楚如何正确执行此操作,但找不到通过一行中的桥接表读取数据的任何好的示例。这可能吗?

【问题讨论】:

使用这种设计,您将永远无法在产品级别看到销售/订单/whatever-the-fact-table-measures。是这个意图吗?示例:Fact 对第 1 组有 1 笔销售。组中有 3 种产品:苹果、香蕉和草莓。你卖了多少草莓? 我知道你在说什么,但是在产品表中我将有产品相关的字段,如类别、生产者等。它不会影响事实表中的度量,纯粹是为了获取每个产品的信息(不是每个产品的销售) 我的设计可能吗?我不需要每个产品的事实表中的特定度量,我只是希望在我加入其他各种维度之后将每个 productGroup 中的项目扩展为一个查询结果,并希望所有产品都显示在一个查询结果行。 有固定上限吗?或者一个组可以包含任意数量的产品? 【参考方案1】:

我认为你只需要不同的表别名:

Select f.*, pmin.*, pmax.*
from Fact f join
     Product pmin
     on pmin.Product_SK = (SELECT MIN(Product_SK)
                           FROM ProductGroup pg
                           WHERE pg.ProductGroup_SK = f.ProductGroup_SK
                          ) join
     Product pmax
     ON pmax.Product_SK = (SELECT MAX(Product_SK)
                           FROM ProductGroup pg
                           WHERE pg.ProductGroup_SK = f.ProductGroup_SK
                          );

不过,这绝对不是我编写查询的方式。 FROM 子句中的子查询令人困惑。而是:

Select f.*, pmin.*, pmax.*
from Fact f join
     (select pg.ProductGroup_SK, max(pg.Product_SK) as maxp, min(pg.Product_SK) as minp
      from ProductGroup pg
      group by pg.ProductGroup_SK
     ) pg
     on pg.ProductGroup_SK = f.ProductGroup_SK join
     Product pmin
     on pmin.Product_SK = pg.minp join 
     Product pmax
     on pmax.Product_SK = pg.maxp;

【讨论】:

感谢您的回复!但是,我使用 min 和 max 的方式只是一种技巧,这对于其中只有 1 个产品或 6 个产品的产品组不起作用,因为这只会显示 2 个产品,不是吗?抱歉,我的问题可能很混乱..【参考方案2】:

鉴于需要产品名称或产品描述来为产品组提供上下文,当与事实结合时,也许这种方法可以工作。

我将其用作参考 SQL Query to concatenate column values from multiple rows in Oracle 来生成以下查询。

/* Step 1: Join Product & Product Group table 
   Step 2: Concatenate Product Names grouped by Product Group on the table retuned from step1.  The Grain of this result table should be same as the product_group dimension.
   Step 3: Joined the result table from step 2 with the fact table */



-- Step 3
Select * 
from fact, 
     -- Step 2:
     (      
    Select  
            product_group_sk,
            LISTAGG(product_name, ', ') WITHIN GROUP (ORDER BY product_group_sk) AS product_name                
        from 
         -- Step 1
         ( 
            Select product_group_sk, 
                   Product_sk, 
                   product_name                
            from product_group pg, product p
            where pg.product_sk = p.product_sk) product_group_list
        group by product_group_list.product_group_sk
    ) product_group_pivoted_list
Where fact.product_group_sk = product_group_pivoted_list.product_group_sk;

【讨论】:

以上是关于Oracle通过带有内部连接和返回n行的子查询的桥表选择查询?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:子查询检查超过 14000 行的子查询优化问题

SQL从每个父行的子行返回最大值

如何处理返回没有行的 IN 子句的子查询

SPARQL使用带有限制的子查询

使用带有比较的子查询 - Oracle

选择带有“is null”子句的查询和子选择/左连接不返回结果