【问题标题】:Diamond structures in SQLSQL 中的菱形结构
【发布时间】:2020-12-08 01:13:39
【问题描述】:

问题

给定以下表结构,其中BC 提供辅助信息,并作为AD 之间的关联表。

A <- B
^    |
|    v
C -> D 

对于A 中的给定记录a,是否有可能检索B 中的数据 C 将其映射到给定值或一组值,在D 中与a 相关的?

示例场景

例如,考虑aA 中的一条记录)代表一家公司,D 包含它可能购买或出售的产品,BC 代表购买和销售价格其中。因此,对于给定的公司a,要求提供采购和销售价格清单是非常合理的,这需要BCD 的组合。

我的第一个想法是将BC 加入到一个复合表中。然后使用复合表将A 中的记录映射到D 中的记录。以下内容可能就足够了:

# SQL Alchemy
prices = B.join(C, B.a_id==C.a_id and B.d_id==C.d_id)
A.join(prices, A.id==prices.a_id).join(D, D.id == prices.D_id)

# SQL (like)
SELECT B.A_ID OR C.A_ID as A_ID, B.PRICE AS B, C.PRICE AS C, B.D_ID OR C.D_ID 
as D_ID,
FROM B, C
WHERE B.D_ID = C.D_ID AND B.A_ID = C.A_ID

虽然我不确定这是解决这个问题的最佳方式。

根据 Gordon Linoff 的建议,我将以下数据作为示例:

         A                               B             
  -----------------             ----------------------  
   ID |   Name                   A_ID | D_ID | Price   
  -----------------             ----------------------  
    1 | A Company                   1 |    1 |    10   
  -----------------                 1 |    3 |    30   
                                ----------------------

         C                                D                               
----------------------             -----------------                                  
 A_ID | D_ID | Price                 ID |   Name                                     
----------------------             -----------------                                  
    1 |    2 |   -20                  1 | Apples                                     
    1 |    3 |   -30                  2 | Bananas
----------------------                3 | Cucumbers
                                   -----------------

想要的结果如下

                         Result (A.ID=1)
             -------------------------------------
                   A     |  B  |  C  |    D
             -------------------------------------
               A Company |  10 |   - | Apples
               A Company |   - | -20 | Bananas
               A Company |  30 | -30 | Cucumbers
             -------------------------------------

最小工作(损坏)示例

根据 Phillipxy 的建议,这里是一个最小的工作 example (Click here @Phillipxy)

注意事项

  • 我在上面使用了 SQL Alchemy 表示法,但我也对纯 SQL 答案感到满意。

  • 我查看了相关问题,将DCD 表一起加入似乎很常见,但我没有发现任何将复合表加入到A 例如A -&gt; (B + D + C)。更重要的是,我还没有看到任何将BC 压缩在一起的答案,这样人们就可以将A 加入D,例如A -&gt; (B + C) -&gt; D。如果有更好的方法以所要求的方式组合所有四个表,我愿意接受建议。

  • 单击 example 按钮将带您到 S.E.带有模拟示例的查询环境(不幸的是,无法在临时表上设置外键)

【问题讨论】:

  • 这使用了模糊的术语。我猜箭头是FK?不需要 FK 和其他约束,也不需要知道查询。表(基表或查询结果)表示关系/关联,查询结果表的关系/关联是通过使用(分别)JOIN 从基表的关系/关联中通过 AND、AND 条件、OR、AND NOT & EXISTS 构造的, WHERE 条件、UNION、EXCEPT 和 SELECT。了解此类表的含义对于查询是必要且足够的。当约束成立时,某些表达式会返回与其他表达式相同的结果,否则不会。
  • @philipxy 箭头表示外键;这是我能用 ASCII 管理的最好的方法(有没有提供实体关系图的方法?)。我还添加了一个 MWE 的链接。
  • use text, not images/links, for text--including tables & ERDs。 (DDL 提供 ERD 内容。)仅将图像用于无法表达为文本或增强文本的内容。在图像中包含图例/键和说明。使用足够多的单词、句子和对部分示例的引用来清楚完整地表达你的意思。在给出业务关系(船)/关联或表(基础或查询结果)时,说明其中的一行根据其列值说明了业务情况。请通过编辑而不是 cmets 进行澄清。
  • 现在您只是要求我们用定制教程重写教科书。遵循已出版的有关信息建模、关系模型和数据库设计与查询的学术教科书。 (用于记录和使用设计的语言和工具的手册不是这样的教科书。)(维基文章或网络帖子也不是。)问一个特定的研究过的非重复问题。 PS 对于代码问题,请提供minimal reproducible example--其中包括剪切、粘贴和可运行代码;作为代码输入的最小代表性示例;期望和实际输出以及明确的规范和解释。
  • @philipxy 我提供了一个问题,一个 MWE,示例数据(导致答案与我的意图不太相符,因此我修改了问题并相应道歉)和一个模型(您必须单击它才能访问它)。由于 SQL 不是我的主要领域,因此术语可能有些用处,但我使用了与我选择的框架 SQL Alchemy 的文档中相同的术语。如果这在介绍性教科书中有所介绍,那么我很高兴有一个链接/参考,但我还没有看到这个确切的场景。

标签: sql join sqlalchemy


【解决方案1】:

假设 B 和 C 在 (a_id,d_id) 上都是唯一的:

SELECT B.PRICE AS B, C.PRICE AS C, D.NAME AS D
FROM D
LEFT JOIN B ON B.D_ID = D.ID
LEFT JOIN C ON C.D_ID = D.ID
WHERE B.PRICE IS NOT NULL OR C.PRICE IS NOT NULL

【讨论】:

  • 感谢您的回答,这对于提出的原始示例是正确的。我真正的问题,也是我发帖的原因,是我把所有东西都绑定到A 时遇到了困难。我已经更新了这个问题以反映这一点,如果我把你弄乱了,我深表歉意。
  • 我已将 Antonin Lejsek 的答案标记为正确,因为它结合了两种方法。再次感谢。
【解决方案2】:

我认为您的解决方案很好,我个人更喜欢 COALESCE 将其缩短一点

SELECT A.Name, M.Sales, M.Purchase, D.Name
FROM A JOIN (
   SELECT 
   COALESCE(B.A_ID, C.A_ID) AS A_ID,      
   B.Price as Sales,
   C.Price as Purchase,
   COALESCE(B.D_ID, C.D_ID) AS D_ID
   FROM B FULL OUTER JOIN C ON B.A_ID = C.A_ID 
                           AND B.D_ID = C.D_ID) M ON A.ID = M.A_ID
JOIN D ON D.ID = M.D_ID  

John M. Owen 的方法也是可以的,加第二张桌子就行了

SELECT A.NAME AS A, B.PRICE AS B, C.PRICE AS C, D.NAME AS D 
FROM A
CROSS JOIN D
LEFT JOIN B ON B.D_ID = D.ID AND B.A_ID = A.ID
LEFT JOIN C ON C.D_ID = D.ID AND C.A_ID = A.ID
WHERE B.PRICE IS NOT NULL OR C.PRICE IS NOT NULL

【讨论】:

    【解决方案3】:

    我发现我可以将BC 这两个表拼接在一起,如下所示:

    SELECT 
       (case when B.A_ID is not null
             then
                 B.A_ID
             else
                 C.A_ID
             end) A_ID,
       B.Price,
       C.Price,
       (case when B.D_ID is not null
             then
                 B.D_ID
             else
                 C.D_ID
             end) D_ID
    FROM B FULL OUTER JOIN C ON B.A_ID = C.A_ID AND B.D_ID = C.D_ID;
    

    将上面的内容与表 AD 结合起来会得到以下查询:

    SELECT A.Name, M.Sales, M.Purchase, D.Name
    FROM A
    JOIN (
    SELECT 
       (case when B.A_ID is not null
            then
                B.A_ID
            else
                C.A_ID
                end) A_ID,
       B.Price as Sales,
       C.Price as Purchase,
       (case when B.D_ID is not null
            then
                B.D_ID
            else
                C.D_ID
                end) D_ID
       FROM B FULL OUTER JOIN C ON B.A_ID = C.A_ID AND B.D_ID = C.D_ID) M ON A.ID = M.A_ID
    JOIN D ON D.ID = M.D_ID  
    

    这读起来有点像弗兰肯斯坦的怪物的爱子,而《大白鲨》中一个从未出现在演职员表中的演员被编码为 ASCII;所以我会在分配 Tick 之前等待更好的建议。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-23
      • 1970-01-01
      • 1970-01-01
      • 2019-08-10
      • 2023-03-22
      • 1970-01-01
      • 2011-02-06
      相关资源
      最近更新 更多