SUM()用于相关表中的多个值

时间:2013-02-22 20:07:30

标签: mysql database-design

我在MySQL数据库中有三个相关的表:

  • inventory_items定义仓库中的类型项
  • inventory_transactions定义添加或删除的广告资源数量
  • 位置定义所述广告资源的位置

Inventory_transactions有一个quantity_offset,用于存储从给定位置添加或删除的给定inventory_item的数量。

我有以下查询,它将获得global_quantity(给定inventory_item_id的所有quantity_offsets的总和)以及location_quantity,只要我知道位置ID,它就会对特定位置执行相同操作。

SELECT sku, name, SUM(quantity_offset) AS global_quantity,
(
SELECT SUM(quantity_offset)
    FROM inventory_transactions
    WHERE inventory_items.inventory_item_id = inventory_transactions.inventory_item_id AND inventory_transactions.location_id = 1
) AS location_quantity
FROM inventory_items
JOIN inventory_transactions ON inventory_items.inventory_item_id = inventory_transactions.inventory_item_id
GROUP BY sku

我最终想要的是为每个位置添加一列,因此结果可能具有以下值:

sku, name, global_quantity, denver_quantity, dallas_quantity, ft_wayne_quantity

我的后备是在单个inventory_item页面上执行此操作(当我知道库存项目并且可以按位置分组时)但是能够在单个查询中执行此操作并将其全部放入一个表格中会非常棒

最初,我原本以为我可以遍历子查询,但无法以编程方式设置列名(在AS中)。

提前感谢您提供的任何帮助。

3 个答案:

答案 0 :(得分:1)

顺便说一句,不是在SELECT列表中使用子查询,而是可以在表达式上使用SUM聚合获得相同的结果,如果行来自给定位置,则有条件地返回quantity_offset。我还会对inventory_transactions表使用LEFT外连接,这样我就可以确保在inventory_items中为每一行返回一行:

SELECT i.sku
     , i.name
     , SUM(t.quantity_offset) AS global_quantity
     , SUM(IF(t.location_id = 1,t.quantity_offset,NULL)) AS location_1_quantity 
  FROM inventory_items i
  LEFT
  JOIN inventory_transactions t ON i.inventory_item_id = t.inventory_item_id
  GROUP BY i.sku

(这不能回答你的问题,但我想让你意识到这一点。)

要回答您的问题,首先,SELECT语句不可能动态更改它在结果集中返回的列的数量或类型。您需要为要返回的每个列定义表达式。 (SQL SELECT语句文本的生成可以动态完成,以生成特定的SELECT语句,但SELECT语句返回的列由SELECT语句修复。)

如果我有一组相对固定的location_id值,并且我需要你指定的结果集,我会多次重复条件表达式的SUM,一次为每个位置或我想要的任何位置集合:

SELECT i.sku
     , i.name
     , SUM(t.quantity_offset) AS global_quantity
     , SUM(IF(t.location_id = 1,t.quantity_offset,NULL)) AS location_1_quantity 
     , SUM(IF(t.location_id = 2,t.quantity_offset,NULL)) AS location_2_quantity 
     , SUM(IF(t.location_id = 3,t.quantity_offset,NULL)) AS location_3_quantity 
     , SUM(IF(t.location_id IN (1,2,3),t.quantity_offset,NULL)) AS location_123_quantity 
     , SUM(IF(t.location_id = 4,t.quantity_offset,NULL)) AS location_4_quantity
  FROM inventory_items i
  LEFT
  JOIN inventory_transactions t ON i.inventory_item_id = t.inventory_item_id
  GROUP BY i.sku

如果要返回的列集需要是真正动态的,那么我根本不会将它们作为列返回。相反,我会将每个位置的SUM(quantity_offset)作为单独的行返回,然后在客户端处理转换为逐列表示。

答案 1 :(得分:1)

你应该使用条件总和 - 这是我所知道的最有效的方式(最快的查询):

SELECT sku, name, SUM(quantity_offset) AS global_quantity,
  sum(case when inventory_transactions.location_id = 1 then quantity_offset else 0 end) as  loc1_quantitity,
  sum(case when inventory_transactions.location_id = 2 then quantity_offset else 0 end) as loc2_quantitity,
  sum(case when inventory_transactions.location_id = 3 then quantity_offset else 0 end) as loc3_quantitity
FROM inventory_items JOIN inventory_transactions ON inventory_items.inventory_item_id = inventory_transactions.inventory_item_id
GROUP BY sku

答案 2 :(得分:0)

试试这个

   SELECT sku, name, SUM(quantity_offset) AS global_quantity,
       (
        SELECT SUM(quantity_offset)
         FROM inventory_transactions
           WHERE inventory_items.inventory_item_id = inventory_transactions.inventory_item_id AND inventory_transactions.location_id = 1
          AND location = denver) AS denver_quantity ,
        (
        SELECT SUM(quantity_offset)
         FROM inventory_transactions
           WHERE inventory_items.inventory_item_id = inventory_transactions.inventory_item_id AND inventory_transactions.location_id = 1
          AND location = dallas) AS dallas_quantity,
         (
        SELECT SUM(quantity_offset)
         FROM inventory_transactions
           WHERE inventory_items.inventory_item_id = inventory_transactions.inventory_item_id AND inventory_transactions.location_id = 1
          AND location = ft_wayne) AS ft_wayne_quantity
   FROM inventory_items
   JOIN inventory_transactions ON inventory_items.inventory_item_id = inventory_transactions.inventory_item_id
   GROUP BY sku

请注意,我使用location作为列名称,我不知道您拥有的位置列名称,只是将其替换为