在多列上组合 sql 内部和外部联接

Posted

技术标签:

【中文标题】在多列上组合 sql 内部和外部联接【英文标题】:Combining sql inner and outer joins over multiple columns 【发布时间】:2015-10-24 12:24:30 【问题描述】:

我遇到了如何在 sql 中的 select 语句中加入以下表格的语法问题。 关系如下:表 abd 有一个内连接。表 b 也有一个到 c 的内连接。表 e 使用 bd 中的字段与 a,b,c,d 进行左连接。

这里是代码。重要的部分在底部。其余的只是表格和计算字段中的字段。它似乎几乎可以工作,因为它可以检索数据。但是,当删除 Futures_Orders 行时,base 会删除 Broker_Commissions 行,因此有些地方不太正确。请记住,Futures_Orders 上没有任何其他表的删除级联集。

SELECT "Futures_Orders"."Date"
    ,"Futures_Orders"."Symbol"
    ,"Futures_Orders"."Contract_Mth"
    ,"Futures_Orders"."Send_To_Broker"
    ,"Futures_Orders"."Order-Id"
    ,"Futures_Orders"."Broker"
    ,"Futures_Orders"."Order_Action"
    ,"Futures_Orders"."No_Contracts"
    ,"Futures_Orders"."Order_Price"
    ,"Futures_Orders"."Trade_Type"
    ,CASE "Futures_Orders"."Order_Action"
        WHEN 'b'
            THEN 's'
        ELSE 'b'
        END "If_Done_Action"
    ,"Futures_Orders"."If_Done_Price"
    ,"Futures_Orders"."No_Contracts" * (
        CASE "Contract_Details"."USIntRates"
            WHEN 'n'
                THEN ABS("Futures_Orders"."Order_Price" - "Futures_Orders"."If_Done_Price") / "Contract_Details"."MinTick"
            ELSE ABS(ABS(TRUNCATE (
                            "Futures_Orders"."Order_Price"
                            ,0
                            ) - TRUNCATE (
                            "Futures_Orders"."If_Done_Price"
                            ,0
                            )) * "Contract_Details"."MinTick" - CASE 
                        WHEN "Contract_Details"."Symbol" IN (
                                'FV'
                                ,'TU'
                                )
                            THEN 400
                        ELSE 200
                        END * ABS("Futures_Orders"."Order_Price" - TRUNCATE (
                            "Futures_Orders"."Order_Price"
                            ,0
                            ) - "Futures_Orders"."If_Done_Price" + TRUNCATE (
                            "Futures_Orders"."If_Done_Price"
                            ,0
                            )))
            END * "Contract_Details"."MinTickVal" / "FX_Rates"."Rate" + CASE 
            WHEN "Broker_Commissions"."Commission" IS NULL
                OR "Broker_Commissions"."Commission_AUD" + "Broker_Commissions"."Commission" = 0
                THEN "Broker"."Commission"
            ELSE "Broker_Commissions"."Commission_AUD" + "Broker_Commissions"."Commission" / "FX_Rates"."Rate"
            END * 2
        ) "Risk"
    ,"Futures_Orders"."Trade_Reason"
    ,"Contract_Details"."MinTick"
    ,"Contract_Details"."MinTickVal"
    ,"Contract_Details"."Symbol"
    ,"Contract_Details"."Currency"
    ,"FX_Rates"."Code"
    ,"Broker"."Broker"
    ,"Broker_Commissions"."Symbol"
    ,"Broker_Commissions"."Broker"
    ,"Broker_Commissions"."ID"
FROM "Futures_Orders"
    ,"Contract_Details"
    ,"Broker"
    ,"FX_Rates"
LEFT JOIN "Broker_Commissions" ON "Broker_Commissions"."Broker" = "Broker"."Broker"
    AND "Broker_Commissions"."Symbol" = "Contract_Details"."Symbol"
WHERE "Contract_Details"."Symbol" = "Futures_Orders"."Symbol"
    AND "Broker"."Broker" = "Futures_Orders"."Broker"
    AND "FX_Rates"."Code" = "Contract_Details"."Currency"

【问题讨论】:

您能否提供示例表数据和您的预期输出?甚至更好 - 一个 jsFiddle 和预期的输出。 表与其他表没有“内部”或“外部”关系。样本数据和期望的结果将有助于解释你在做什么。此外,您尝试过的查询并解释为什么它不起作用可以深入了解您的问题。 【参考方案1】:

我认为您需要类似的东西。

<field> 对于每个关系都不同,但您没有提供

 SELECT 
 FROM a
 INNER JOIN b
         ON a.<field> = b.<field>
 INNER JOIN d
         ON a.<field> = d.<field>
 INNER JOIN c
         ON b.<field> = c.<field>
 LEFT JOIN e
         ON e.<field> = b.<field>
        AND e.<field> = d.<field>

【讨论】:

此代码在添加、检索和修改行时运行良好。但是,当我尝试删除一行时,我收到以下错误消息:删除指定记录时出错。 JDBC 调用中的无效参数:参数索引超出范围:1. 我还注意到 base 将连接代码更改为以下内容: 您不能同时从多个连接表中删除记录。为每个表编写单独的删除语句。 Libreoffice Base,这是我正在使用的前端,正在执行行的添加、删除和修改。我所做的只是编写查询,其余的由它完成。【参考方案2】:

假设您要连接的列在两个表中的名称相同(并且没有重复导致歧义),我们可以使用 NATURAL 来简化语法。

d NATURAL LEFT JOIN (a NATURAL JOIN (b NATURAL JOIN c) NATURAL JOIN d)

您可以将NATURAL ... JOIN X 替换为JOIN X ON (COLA = COLB) 语法

你的实际例子不同,可以这样写:

FROM "Futures_Orders" NATURAL JOIN "Contract_Details"
 NATURAL JOIN "Broker"
 INNER JOIN "FX_Rates" ON ("FX_Rates"."Code" = "Contract_Details"."Currency")
 NATURAL LEFT JOIN "Broker_Commissions"

如果您使用 NATURAL 连接,则必须在查询中引用同名的列而不使用它们的表名。

你提到了 Base(OpenOffice 或 LibreOffice),它有自己的预处理器和语法差异,可以修改查询,有时是错误的。

【讨论】:

我第一次看到这种语法。 ((b NATURAL JOIN c) NATURAL JOIN d)) 不需要括号? 可以去掉 (b Natural JOIN c) 周围的括号。

以上是关于在多列上组合 sql 内部和外部联接的主要内容,如果未能解决你的问题,请参考以下文章

外部联接中的内部联接导致性能不足,有啥不同的方法?

SQL Server-外部联接基础回顾(十三)

SQL:跨两个层次结构的完全外部联接

外部联接中的内部异常

外部连接的位置vs ON

完全外部联接SQL Server