3

我想知道如何从TBL_ITEMget中引用三列SUM(QTY) FROM TBL_INVTY

TBL_ITEM

+------+-------------+----------+
| CODE | PARENT_CODE | OLD_CODE |
+------+-------------+----------+
|    2 |        NULL |       20 |
|   2A |           2 |     NULL |
|   2B |           2 |     NULL | 
|    3 |        NULL |     NULL |
|    4 |        NULL |     NULL |
|   20 |        NULL |     NULL |
+------+-------------+----------+

TBL_INVTY

+------+-----+
| CODE | QTY |
+------+-----+
|    2 |   2 |
|   2A |   4 |
|   2B |   1 |
|    3 |   3 |
|    4 |   5 |
|   20 |   2 |
+------+-----+

并且,到达这个:

+------+-----+
| CODE | QTY |
+------+-----+
|    2 |   9 |
|    3 |   3 |
|    4 |   5 |
+------+-----+

最后一张表的第一行的WHERE CODE=2aQTY为 9,因为我SUM(QTY) from TBL_INVTY WHERE CODE IN (20, 2A, 2B, 2)TBL_ITEM.

4

1 回答 1

3

诀窍是从 tbl_item 获取两列结果集。我称之为“匹配”和“地图”的两列。“匹配”列中的值是我们将在 JOIN 谓词中使用的值,以查找“匹配”行。但是我们要从 map 列返回值,然后对其进行 GROUP BY。

对于您的示例,我认为此查询为我们提供了我们需要的结果集:

SELECT IF(i.old_code IS NOT NULL,i.old_code,i.code) AS `match`
     , IF(i.parent_code IS NOT NULL,i.parent_code,i.code) AS map
  FROM tbl_item i
  LEFT
  JOIN tbl_item j
    ON j.old_code = i.code
 WHERE j.old_code IS NULL
 UNION ALL
SELECT k.code
     , k.code
  FROM tbl_item k
 WHERE k.old_code IS NOT NULL

这应该给出这个结果集:

+-------+-------+
| match | map   |
+-------+-------+
|   20  |   2   |
|   2A  |   2   |
|   2B  |   2   |
|    3  |   3   |
|    4  |   4   |
|    2  |   2   |
+-------+-------+

我们需要确保“匹配”列是唯一的,这样我们就不会无意中将 tbl_invty 中的一行匹配到该集合中的多行。在这组数据中这不是问题,但在更一般的情况下可能是。此外,这只会从旧到新的“一个级别”。如果“新”代码稍后被取代,则此查询将找不到“最新”代码,只会找到该行中的值。同样,这个数据不是问题,但更一般的情况下,这可能是一个问题。

(还有其他编写查询的方法,例如使用 CASE 表达式,而不是 IF,或者更简洁:

SELECT IFNULL(i.old_code,i.code) AS `match`
     , IFNULL(i.parent_code,i.code) AS map
  FROM tbl_item i 
  LEFT
  JOIN tbl_item j
    ON j.old_code = i.code
 WHERE j.old_code IS NULL
 UNION ALL
SELECT k.code
     , k.code
  FROM tbl_item k
 WHERE k.old_code IS NOT NULL      

无论如何,一旦我们有一个查询可以为我们提供合适的结果集,我们就可以轻松获得 SUM(QTY)。我们只是将该查询用作另一个查询中的行源。(我们称其为“内联视图”,尽管 MySQL 称其为“派生表”,更准确地描述了 MySQL 实际处理视图查询的方式。)

SELECT m.map      AS CODE
     , SUM(v.qty) AS QTY
  FROM tbl_invty v
  JOIN (
         SELECT IFNULL(i.old_code,i.code) AS `match` 
              , IFNULL(i.parent_code,i.code) AS map 
           FROM tbl_item i 
           LEFT 
           JOIN tbl_item j 
             ON j.old_code = i.code 
          WHERE j.old_code IS NULL 
          UNION ALL
         SELECT k.code
              , k.code
           FROM tbl_item k
          WHERE k.old_code IS NOT NULL
       ) m 
    ON m.match = v.code 
 GROUP 
    BY m.map 

跟进

问:如果 CODE 同时具有 PARENT_CODE 和 OLD_CODE 怎么办(我刚刚发现这是一种可能的情况,...

答:您需要测试查询以返回“匹配”和“映射”代码。

鉴于这种新情况(同时具有 PARENT_CODE 和 OLD_CODE 的行),需要进行调整。您确实需要遍历每个案例,并确定每个案例应该返回什么。

似乎我们想要获取表中的每个代码(无论是在 CODE 列、PARENT_CODE 列还是 OLD_CODE 列中)作为“匹配”代码,并为每个代码派生适当的“映射”代码。

我将假设表中的 CODE 列不是 NULL tbl_item(只是为了简化这一点。)

这些是我正在考虑的四个查询,用于处理所有这些情况:

-- rows with PARENT_CODE,  match=CODE map=PARENT_CODE
SELECT i.code AS `match_code`
     , i.parent_code AS `map_code`
  FROM tbl_item i
 WHERE i.parent_code IS NOT NULL


-- rows with PARENT_CODE and OLD_CODE,  match=OLD_CODE map=PARENT_CODE
SELECT j.old_code
     , j.parent_code
  FROM tbl_item j
 WHERE j.parent_code IS NOT NULL
   AND j.old_code IS NOT NULL 

-- rows with no PARENT_CODE,  match=CODE map=CODE   
SELECT k.code
     , k.code
  FROM tbl_item k
 WHERE k.parent_code IS NULL

-- rows with OLD_CODE and no PARENT_CODE,  match=OLD_CODE map=CODE
SELECT l.old_code
     , l.code
  FROM tbl_item l
 WHERE l.parent_code IS NULL
   AND l.old_code IS NOT NULL

这些将使用 UNION ALL 运算符组合在一起。

我可以设想古怪的数据,其中相同的 CODE 出现不止一次,并且每个可能指向不同的 PARENT_CODE

TBL_ITEM 中的一些古怪(意外)行示例。

+------+-------------+----------+
| CODE | PARENT_CODE | OLD_CODE |
+------+-------------+----------+
|  77A |         77A |     NULL |
|  77A |         77B |      77A |
|   77 |          77 |      77A |
|   77 |         77A |     NULL |
+------+-------------+----------+

面对这样的烂摊子,我们该怎么办?

就获得 SUM(QTY) 而言,我们需要在“映射/匹配”行集中确保给定的 CODE 只出现一次。(如果我们在那里得到倍数,那么 SUM 就会太高,因为我们要匹配多个......

快速解决方法是将查询包装在另一个查询中,以消除重复并只选择一个要映射的代码。这可能不是“正确”的修复,但它为我们提供了一个可以使用的结果集:

SELECT u.match
     , MIN(u.map) AS map
  FROM (
          -- query to get match/map rowset here
       ) u
 GROUP BY u.match

然后,我们将此查询用作获取 SUM(QTY) 的内联视图,与之前的查询相同。我们刚刚在别名为 的内联视图中更改了该查询m

SELECT m.map      AS CODE
     , SUM(v.qty) AS QTY
  FROM tbl_invty v
  JOIN (
         SELECT u.match
              , MIN(u.map) AS map
           FROM (
                  -- query to get match/map rowset here
                ) u
          GROUP BY u.match
       ) m 
    ON m.match = v.code 
 GROUP
    BY m.map

在这一点上,几乎不用说,为了使查询变得简单,我们真正想要的是 a 只有两列,a(唯一非 nullmatch_code和 optional map_code

这将是一个非常简单的查询:

SELECT IFNULL(m.map_code,m.match_code) AS CODE
     , SUM(v.qty) AS QTY
  FROM tbl_invty v
  JOIN tbl_match_map m
    ON m.match_code = v.code
 GROUP
    BY IFNULL(m.map_code,m.match_code)

它正在从给定的表中生成“tbl_match_map”行集,这是一项艰巨的工作。

于 2013-07-18T06:34:21.337 回答