Mysql JOIN具有额外的优先级列

时间:2014-07-03 10:13:22

标签: mysql sql database

我有两天时间试图做这个查询而没有运气。 我有两张桌子' DEMAND'和' DEMAND_STATE' (一对多关系)表DEMAND_STATE有数百万条目。

CREATE TABLE DEMAND
(
   ID          INT            NOT NULL,
   DESTINY_ID  INT            NOT NULL
)

CREATE TABLE DEMAND_STATE
(
   ID         INT      NOT NULL,
   PRIORITY   INT      NOT NULL,
   QUANTITY   DOUBLE   NOT NULL,
   CASE_ID    INT      NOT NULL,
   DEMAND_ID  INT      NOT NULL,
   PHASE_ID   INT      NOT NULL
)

根据CASE_ID和PHASE_ID给出DEMAND_STATE的QUANTITY。我们有N' N'在' M'案例。在所有案例中始终使用相同数量的阶段。我们总是有一个名为' BASE CASE'的初始基本数量。在CASE_ID = 1的情况下。

例如,获取Case(id = 2)和Case Base(id = 1)

的数量
select D.*, S.PRIORITY, S.QUANTITY, S.CASE_ID, S.DEMAND_ID, S.PHASE_ID
FROM DEMAND D 
join DEMAND_STATE S on (D.ID = S.DEMAND_ID)
WHERE (S.CASE_ID = 2 OR S.CASE_ID = 1)   

(仅适用于id = 8)

ID  PRIORITY    QUANTITY    CASE_ID DEMAND_ID   PHASE_ID
8   0   85  1   8   1
8   0   83  1   8   2
8   0   88  1   8   3
8   0   89  1   8   4

8   10  85  2   8   1
8   10  84  2   8   2
8   10  86  2   8   3
8   10  89  2   8   4

我们需要在“需求”中获取所有需求。只有具有MAX优先级的每个阶段的数量。这个想法是每个新案例创建都没有重复的DEMAND_STATE数据。只有在Demand-Case-Phase与Case Base不同时才创建新的状态行。这是一个新项目,我们接受模型的更改以获得更好的性能。

我也尝试过MAX计算。对DEMAND_STATE的查询工作正常,但只获取具体DEMAND_ID的数据。此外,我认为这个解决方案可能非常昂贵。

SELECT P.ID, P.QUANTITY, P.CASE_ID, P.DEMAND_ID, P.PHASE_ID
FROM DEMAND_STATE P
    JOIN (
        SELECT PHASE_ID, MAX(PRIORITY) max_priority, S.DEMAND_ID
        from DEMAND_STATE S
        WHERE S.DEMAND_ID = 1
    AND (S.CASE_ID=1 OR S.CASE_ID=2)
        GROUP BY S.PHASE_ID
    ) SUB 
ON (SUB.PHASE_ID = P.PHASE_ID AND SUB.max_priority = P.PRIORITY)
WHERE P.DEMAND_ID = 1
GROUP BY P.PHASE_ID 

结果:

ID  QUANTITY    CASE_ID DEMAND_ID   PHASE_ID
1   86  1   1   1
2   85  1   1   2
3   81  1   1   3
8   500 2   1   4

这是预期的结果:

ID  ID  PRIORITY    QUANTITY    CASE_ID PHASE_ID
8   1   0   86  1   1       (data from Case Base id=1 priority 0)
8   2   10  85  1   2       (data from Case Baseid=1 priority 0)
8   3   10  81  1   3       (data from Case Base id=1 priority 0)
8   64  10  500 2   4       (data from Case id=2 priority 10)

感谢您的帮助:)

编辑:

Simon提案的结果:

ID  QUANTITY    CASE_ID DEMAND_ID   PHASE_ID
1   86  1   1   1
2   85  1   1   2
3   81  1   1   3
4   84  1   1   4    (this row shouldnt exist)
8   500 2   1   4    (this is the correct row)

还必须加入DEMAND

@didierc回复:

ID  ID  MAX(S.PRIORITY) QUANTITY    CASE_ID PHASE_ID
1   8   10  500 2   4
2   13  10  81  2   1
2   14  10  83  2   2
2   15  10  84  2   3
3   21  10  81  2   1
4   31  10  86  2   3
4   32  10  80  2   4
4   29  10  85  2   1
4   30  10  81  2   2

我们需要每个DEMAND四行,数量为Value。在Case Base中我们有四个数量,在Case 2中我们只改变第4阶段的数量。我们每个需求总共需要四行。

数据库DEMAND_STATE数据:

ID  PRIORITY    QUANTITY    CASE_ID DEMAND_ID   PHASE_ID
1   0   86  1   1   1
2   0   85  1   1   2
3   0   81  1   1   3
4   0   84  1   1   4

8   10  500 2   1   4

2 个答案:

答案 0 :(得分:0)

如果我正确理解您的问题,子查询的使用应该能够按照您的意愿进行。以下内容:

SELECT
    P.ID, 
    P.QUANTITY, 
    P.CASE_ID, 
    P.DEMAND_ID, 
    P.PHASE_ID
FROM DEMAND_STATE P

INNER JOIN (
    -- Next level up groups it down and so gets the rows first returned for each PHASE_ID, which is the highest priority due to the subquery
    SELECT
        D.PHASE_ID,
        D.PRIORITY,
        D.DEMAND_ID
    FROM (
        -- Top level query to get all rows and order them in desc priority order
        SELECT 
            S.PHASE_ID, 
            S.PRIORITY, 
            S.DEMAND_ID
        FROM DEMAND_STATE S
        WHERE S.DEMAND_ID IN (1) -- Update this to be whichever DEMAND_IDs you are interested in
        AND S.CASE_ID IN (1,2)
        ORDER BY 
            S.PHASE_ID ASC,
            S.DEMAND_ID ASC,
            S.PRIORITY DESC
    ) D
    GROUP BY 
        D.PHASE_ID,
        S.DEMAND_ID
) SUB
ON SUB.PHASE_ID = P.PHASE_ID
AND SUB.DEMAND_ID = P.DEMAND_ID

存在顶级子查询以获取您感兴趣的行,并按顺序对它们进行排序,这些顺序允许在PHASE_ID和DEMAND_ID对其进行分组时产生可预测的结果。这反过来允许一个简单的INNER JOIN到DEMAND_STATE希望(除非我误解了你的查询)

这可能仍然很昂贵,但取决于该顶级查询中的数据量。

答案 1 :(得分:0)

  

我们需要在“需求”中获取所有需求。只有MAX优先级的每个阶段的数量

根据您的示例结果集,我将上述内容翻译为:

SELECT 
  D.ID, S.ID, MAX(S.PRIORITY), S.QUANTITY, S.CASE_ID, S.PHASE_ID
FROM DEMAND D
LEFT JOIN DEMAND_STATE S
ON D.ID = S.DEMAND_ID
GROUP BY S.PHASE_ID, S.DEMAND_ID

更新

要获得每对的最大优先级(demand_id,phase_id),我们使用以下查询:

SELECT
  DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
FROM DEMAND_STATE
GROUP BY DEMAND_ID, PHASE_ID

接下来,要检索给定需求的一组阶段,只需创建一个内部联接按需状态:

SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
  SELECT
    DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
  FROM DEMAND_STATE
  GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, PRIORITY)
WHERE DEMAND_ID = 1

如果要限制可能的情况,请在查询S2中包含where子句:

SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
  SELECT
    DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
  FROM DEMAND_STATE
  WHERE CASE_ID IN (1,2)
  GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, PRIORITY)
WHERE DEMAND_ID = 1

但是,您的评论和更新表明MAX(PRIORITY)似乎并不是非常相关。我的理解是你有一个基本案例,可以在给定场景中被另一个案例覆盖(该场景是对基础案例+其他一些案例)。如果这不正确,请澄清问题正文中的这一点。如果是这种情况,您可以通过PRIORITY替换CASE_ID来更改上述查询:

SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
  SELECT
    DEMAND_ID, PHASE_ID, MAX(CASE_ID) AS CASE_ID
  FROM DEMAND_STATE
  WHERE CASE_ID IN (1,2)
  GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, CASE_ID)
WHERE DEMAND_ID = 1

我从优先权中看到的唯一原因是,如果您希望合并超过2个案例,并使用优先权来选择哪个案例将取决于阶段。


您当然可以在DEMAND上添加内部联接以包含相关的需求数据。