sql一个表的两列引用另一个表的同一列

时间:2017-11-30 11:16:46

标签: sql postgresql foreign-keys

我有两张桌子 table:product1_id不为null且cost2_id可为空的产品

   id    | cost1_id | cost2_id
   1     | 1        | 2
   2     | 3        | 

表:费用

   id    | value    | currency
   1     | 15       | EUR
   2     | 20       | USD
   3     | 100      | TND

我想在不使用join的情况下得到这个结果(我宁愿使用UNION,因为我有大型数据库)

product_id | cost1_value | cost1_currency | cost2_value | cost2_currency 
     1     | 15          | EUR            |  20         |  USD
     2     | 100         | TND            |             |

2 个答案:

答案 0 :(得分:3)

我可以想到最小化连接的一个选项是......

SELECT
    product.id    AS product_id,
    MAX(CASE WHEN cost.id = product.cost1_id THEN cost.value    END)   AS cost1_value,
    MAX(CASE WHEN cost.id = product.cost1_id THEN cost.currency END)   AS cost1_currency,
    MAX(CASE WHEN cost.id = product.cost2_id THEN cost.value    END)   AS cost2_value,
    MAX(CASE WHEN cost.id = product.cost2_id THEN cost.currency END)   AS cost2_currency
FROM
    product
LEFT JOIN
    cost
        ON cost.id IN (product.cost1_id, product.cost2_id)
GROUP BY
    product.id

也就是说,使用IN()可能会比仅加入两次更慢......


确保表上有索引。 他们 是优化联接的方法,而不是试图避免它们......

  • 在这种情况下,您可能只需要Cost表中的群集主键...

因此,我强烈建议您至少 尝试"正常"这样做的方式......

SELECT
    product.id    AS product_id,
    c1.value      AS cost1_value,
    c1.currency   AS cost1_currency,
    c2.value      AS cost2_value,
    c2.currency   AS cost2_currency
FROM
    product
LEFT JOIN
    cost    c1
        ON c1.id = product.cost1_id
LEFT JOIN
    cost    c2
        ON c2.id = product.cost2_id

<强> 编辑:

另一个深奥的选择可能是......

SELECT
    product_id,
    MAX(cost1_value)       AS cost1_value,
    MAX(cost1_currency)    AS cost1_currency,
    MAX(cost2_value)       AS cost2_value,
    MAX(cost2_currency)    AS cost2_currency
FROM
(
    SELECT
        product.id                                       AS product_id,
        cost.value                                       AS cost1_value,
        cost.currency                                    AS cost1_currency,
        CASE WHEN 1=0 THEN cost.value    ELSE NULL END   AS cost2_value,
        CASE WHEN 1=0 THEN cost.currency ELSE NULL END   AS cost2_currency
    FROM
        product
    LEFT JOIN
        cost
            ON cost.id = product.cost1_id

    UNION ALL

    SELECT
        product.id                                       AS product_id,
        NULL                                             AS cost1_value,
        NULL                                             AS cost1_currency,
        cost.value                                       AS cost2_value,
        cost.currency                                    AS cost2_currency
    FROM
        product
    INNER JOIN
        cost
            ON cost.id = product.cost2_id
)
    unioned
GROUP BY
    product_id

然后创建这些索引......

CREATE INDEX ix_product_cost1 ON product(cost1_id, id);
CREATE INDEX ix_product_cost2 ON product(cost2_id, id);

可能 稍快一些,但代价是显着增加的复杂性 成为维护将来头疼。

答案 1 :(得分:0)

试试这个答案,这个答案适用于SQL Server。在PostgreSQL中尝试相同的方法。

CREATE table #Product(ID INT,Cost1_id INT,Cost2_id INT)
INSERT INTO #Product VALUES(1,1,1)
INSERT INTO #Product VALUES(2,3,0)

CREATE table #Cost(ID INT,Value INT,currency VARCHAR(10))
INSERT INTO #Cost VALUES(1,15,'EUR')
INSERT INTO #Cost VALUES(2,20,'USD')
INSERT INTO #Cost VALUES(3,100,'TND')

SELECT ID product_id,MAX(cost1_value)cost1_value,MAX(cost1_Currency)cost1_Currency
        ,MAX(cost2_value)cost2_value,MAX(cost2_Currency)cost2_Currency
FROM(
    SELECT P.ID,C.Value cost1_value,C.Currency cost1_Currency,0 AS cost2_value,'' AS cost2_Currency
    from #Cost C, #Product P
    WHERE P.Cost1_id=C.Id
    UNION ALL
    SELECT P.ID,0 AS cost2_value,'' AS cost2_Currency,C.Value ,C.Currency 
    from #Cost C, #Product P
    WHERE P.Cost2_id=C.Id
    )D
GROUP BY ID

希望这会对你有所帮助。