什么是一种清晰的方法来使用实体-属性-值表连接表格?

huangapple go评论106阅读模式
英文:

What's a clean way to join tables with Entity-Attribute-Value?

问题

我在想我是否以最有效的方式进行操作。

我有一个数据库表,其中包含自定义数据元素。要查看哪些记录使用自定义对象表中的数据,我必须连接三个ID号,以及指定描述。这并不是太糟糕,但有时我的SQL脚本中可能有多达30个这样的连接,这可能会很冗长。我想知道是否有更清晰的编码方式?也许可以使用临时存储过程或临时函数吗?

SELECT
    r.ID, 
    apples.status, 
    oranges.status, 
    bananas.status 
FROM
    record r
LEFT JOIN 
    custom_object apples ON apples.T_ID1 = r.T_ID1
                         AND apples.T_ID2 = r.T_ID2
                         AND apples.T_ID3 = r.T_ID3
                         AND apples.DESC = 'Apples'
LEFT JOIN 
    custom_object oranges ON oranges.ID1= r.T_ID1
                          AND oranges.T_ID2 = r.T_ID2
                          AND oranges.T_ID3 = r.T_ID3
                          AND oranges.DESC = 'Oranges'
LEFT JOIN 
    custom_object bananas ON bananas.T_ID1= r.T_ID1
                          AND bananas.T_ID2 = r.T_ID2
                          AND bananas.T_ID3 = r.T_ID3
                          AND bananas.DESC = 'Bananas'
英文:

I am wondering if I'm doing this in the most efficient way possible.

I have a database table that houses custom data elements. To see what records use the data in the custom object table I have to join on 3 ID numbers, as well as specify the description. It's not that bad, but sometimes I can have up to 30 of these joins in my SQL script and that can be long. I was wondering if there is a cleaner way to code this? Maybe with a temp stored procedure or temp function?

SELECT
    r.ID, 
    apples.status, 
    oranges.status, 
    bananas.status 
FROM
    record r
LEFT JOIN 
    custom_object apples ON apples.T_ID1 = r.T_ID1
                         AND apples.T_ID2 = r.T_ID2
                         AND apples.T_ID3 = r.T_ID3
                         AND apples.DESC = 'Apples'
LEFT JOIN 
    custom_object oranges ON oranges .ID1= r.T_ID1
                          AND oranges.T_ID2 = r.T_ID2
                          AND oranges.T_ID3 = r.T_ID3
                          AND oranges.DESC = 'Oranges'
LEFT JOIN 
    custom_object bananas ON bananas.T_ID1= r.T_ID1
                          AND bananas.T_ID2 = r.T_ID2
                          AND bananas.T_ID3 = r.T_ID3
                          AND bananas.DESC = 'Bananas'

答案1

得分: 1

使用带有案例表达式的单个连接在这里似乎是一个更简单的方法。

SELECT
    r.ID, 
    AppleStatus = CASE WHEN co.[DESC] = '苹果' THEN co.status END,
    OrangeStatus = CASE WHEN co.[DESC] = '橙子' THEN co.status END, 
    BananaStatus = CASE WHEN co.[DESC] = '香蕉' THEN co.status END 
FROM record r
LEFT JOIN custom_object co ON co.T_ID1 = r.T_ID1
                         AND co.T_ID2 = r.T_ID2
                         AND co.T_ID3 = r.T_ID3
                         AND co.[DESC] IN ('苹果', '橙子', '香蕉')
英文:

Using a single join with a case expression seems like a much simpler approach here.

SELECT
    r.ID, 
    AppleStatus = case when co.[DESC] = 'Apples' then co.status end,
    OrangeStatus = case when co.[DESC]= 'Oranges' then co.status end, 
    BananaStatus = case when co.[DESC] = 'Bananas' then co.status end 
FROM record r
LEFT JOIN custom_object co ON co.T_ID1 = r.T_ID1
                         AND co.T_ID2 = r.T_ID2
                         AND co.T_ID3 = r.T_ID3
                         AND co.[DESC] in ('Apples', 'Oanges', 'Bananas')

答案2

得分: 1

条件聚合是可能的:

SELECT
    r.ID,
    MAX(CASE WHEN co.[DESC] = 'Apples' THEN co.status END) AS applesStatus, 
    MAX(CASE WHEN co.[DESC] = 'Oranges' THEN co.status END) AS orangesStatus, 
    MAX(CASE WHEN co.[DESC] = 'Bananas' THEN co.status END) AS bananasStatus
FROM
    record r
LEFT JOIN 
    custom_object co ON co.T_ID1 = r.T_ID1
                     AND co.T_ID2 = r.T_ID2
                     AND co.T_ID3 = r.T_ID3
                     AND co.[DESC] IN ('Apples', 'Oranges', 'Bananas') -- optional
GROUP BY r.ID

OUTER APPLY 中执行相同的操作将避免外部的 GROUP BY 并在构建查询的其余部分时提供更多的灵活性:

SELECT
    r.ID,
    statuses.*
FROM
    record r
OUTER APPLY ( 
    SELECT
        MAX(CASE WHEN co.[DESC] = 'Apples' THEN co.status END) AS applesStatus, 
        MAX(CASE WHEN co.[DESC] = 'Oranges' THEN co.status END) AS orangesStatus, 
        MAX(CASE WHEN co.[DESC] = 'Bananas' THEN co.status END) AS bananasStatus
    FROM custom_object co
    WHERE co.T_ID1 = r.T_ID1
        AND co.T_ID2 = r.T_ID2
        AND co.T_ID3 = r.T_ID3
        AND co.[DESC] IN ('Apples', 'Oranges', 'Bananas') -- optional
) statuses

还可以使用公共表达式(CTE):

; WITH statuses AS (
    SELECT
        co.T_ID1, co.T_ID2, co.T_ID3,
        MAX(CASE WHEN co.[DESC] = 'Apples' THEN co.status END) AS applesStatus, 
        MAX(CASE WHEN co.[DESC] = 'Oranges' THEN co.status END) AS orangesStatus, 
        MAX(CASE WHEN co.[DESC] = 'Bananas' THEN co.status END) AS bananasStatus
    FROM custom_object co
    WHERE co.[DESC] IN ('Apples', 'Oranges', 'Bananas') -- optional
    GROUP BY co.T_ID1, co.T_ID2, co.T_ID3
)
SELECT
    r.ID,
    s.applesStatus,
    s.orangesStatus,
    s.bananasStatus
FROM
    record r
LEFT JOIN 
    statuses s ON s.T_ID1 = r.T_ID1
               AND s.T_ID2 = r.T_ID2
               AND s.T_ID3 = r.T_ID3

以上所有的操作都假设在相同的ID组合下没有重复的属性。

为了获得最佳性能,您应该在 custom_object(T_ID1, T_ID2, T_ID3, [DESC]) 上定义一个索引。

示例结果:

ID applesStatus orangesStatus bananasStatus
1 Apples1 Oranges1 Bananas1
2 Apples2 null null
3 null Oranges3 null
4 null null Bananas4
5 null null null
6 Apples6 null Bananas6

查看此 db<>fiddle

英文:

Conditional aggregation is a possibility:

SELECT
    r.ID,
    MAX(CASE WHEN co.[DESC] = &#39;Apples&#39; THEN co.status END) AS applesStatus, 
    MAX(CASE WHEN co.[DESC] = &#39;Oranges&#39; THEN co.status END) AS orangesStatus, 
    MAX(CASE WHEN co.[DESC] = &#39;Bananas&#39; THEN co.status END) AS bananasStatus
FROM
    record r
LEFT JOIN 
    custom_object co ON co.T_ID1 = r.T_ID1
                         AND co.T_ID2 = r.T_ID2
                         AND co.T_ID3 = r.T_ID3
                         AND co.[DESC] IN (&#39;Apples&#39;, &#39;Oranges&#39;, &#39;Bananas&#39;) -- optional
GROUP BY r.ID

The same inside an OUTER APPLY will avoid the outer GROUP BY and allow more flexibility as you build out the rest of your query.

SELECT
    r.ID,
    statuses.*
FROM
    record r
OUTER APPLY ( 
    SELECT
        MAX(CASE WHEN co.[DESC] = &#39;Apples&#39; THEN co.status END) AS applesStatus, 
        MAX(CASE WHEN co.[DESC] = &#39;Oranges&#39; THEN co.status END) AS orangesStatus, 
        MAX(CASE WHEN co.[DESC] = &#39;Bananas&#39; THEN co.status END) AS bananasStatus
    FROM custom_object co
    WHERE co.T_ID1 = r.T_ID1
        AND co.T_ID2 = r.T_ID2
        AND co.T_ID3 = r.T_ID3
        AND co.[DESC] IN (&#39;Apples&#39;, &#39;Oranges&#39;, &#39;Bananas&#39;) -- optional
) statuses

A Common Table Expression (CTE) can also be used:

; WITH statuses AS (
    SELECT
        co.T_ID1, co.T_ID2, co.T_ID3,
        MAX(CASE WHEN co.[DESC] = &#39;Apples&#39; THEN co.status END) AS applesStatus, 
        MAX(CASE WHEN co.[DESC] = &#39;Oranges&#39; THEN co.status END) AS orangesStatus, 
        MAX(CASE WHEN co.[DESC] = &#39;Bananas&#39; THEN co.status END) AS bananasStatus
    FROM custom_object co
    WHERE co.[DESC] IN (&#39;Apples&#39;, &#39;Oranges&#39;, &#39;Bananas&#39;) -- optional
    GROUP BY co.T_ID1, co.T_ID2, co.T_ID3
)
SELECT
    r.ID,
    s.applesStatus,
    s.orangesStatus,
    s.bananasStatus
FROM
    record r
LEFT JOIN 
    statuses s ON s.T_ID1 = r.T_ID1
               AND s.T_ID2 = r.T_ID2
               AND s.T_ID3 = r.T_ID3

The above all assume no duplicate properties per ID combination.

For best performance, you should define an index on custom_object(T_ID1, T_ID2, T_ID3, [DESC]).

Sample results:

ID applesStatus orangesStatus bananasStatus
1 Apples1 Oranges1 Bananas1
2 Apples2 null null
3 null Oranges3 null
4 null null Bananas4
5 null null null
6 Apples6 null Bananas6

See this db<>fiddle.

huangapple
  • 本文由 发表于 2023年2月16日 04:05:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464934.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定