SQL连接具有不同级别细节的两个表

时间:2018-06-21 06:24:48

标签: sql postgresql

所以我有两个销售表,预算表和实际表。

“预算”有两列:位置和销售。例如,

位置销售
24 $ 20000
36 $ 100300
40 $ 24700
总计$ 145000

“实际”具有三列:发票编号,位置和销售。例如,

发票位置销售
10000 36 $ 5000
10001 40 $ 6000
10002 99 $ 7000
等等
总计$ 110000

总而言之,“实际”在发票级别记录交易,而“预算”仅在地点级别记录(没有单独的发票)。

我正在尝试创建一个汇总表,该表并排列出按位置分组的实际销售额和预算销售额。实际列的总和应为110000美元,预算为145000美元。这是我的尝试(在pgAdmin / postgresql上):

SELECT actual.location, SUM(actual.sales) AS actual_sales, SUM(budget.sales) AS budget_sales   
FROM actual LEFT JOIN budget 
ON actual.location = budget.location 
GROUP BY actual.location;

我之所以使用LEFT JOIN,是因为“实际”所在的位置没有“预算”所在的位置(例如,位置99)。

最后,我在actual_sales和budget_sales列上都得到了一些巨大的数字(百万美元),远远超过了实际总数(110000美元)或预算销售额(145,000美元)。

这是因为编写查询的方式基本上是要求SQL将“实际”中的每个发票都连接到“预算”中的每一行,因此重复了很多次?如果是这样,我应该怎么写呢?

谢谢!

4 个答案:

答案 0 :(得分:0)

查询对我来说很好。但是,很难找出数字错误的原因。我的建议是,您将预算和实际支出按地点分别计入2个临时表中,然后使用LEFT JOIN将其汇总在一起。

答案 1 :(得分:0)

是的,您要为每个实际的销售行一次加入预算。但是,除非同一位置有多个预算行,否则您的“实际销售额”总和不应该更大。您应该检查一下,因为听起来不应该如此。

在这种情况下,您需要做的是首先在CTE或子查询中将实际销售额相加,然后再将结果加入预算。这样,每个位置只有一行。这样做是为了实际销售。如果确实有一个预算位置的行也有多个,则可能还需要以相同的方式对预算进行子查询。

Select Act.Location, Act.actual_sales, budget.sales as budget_sales
From
(
SELECT actual.location, SUM(actual.sales) AS actual_sales
FROM actual
GROUP BY actual.location
) Act
left join budget on Act.location = budget.location 

答案 2 :(得分:0)

根据您的描述,您似乎在两个表中都有重复项。有多种方法可以解决此问题。这是使用union allgroup by的一个:

select Location, 
       sum(actual_sales) as actual_sales,
       sum(budget_sales) as budget_sales
from ((select a.location, a.sales as actual_sales, null as budget_sales
       from actual a
      ) union all
      (select b.location, null, b.sales
       from budget b
      )
     ) ab
group by location;

此结构保证与表无关,每个值仅计数一次。

答案 3 :(得分:0)

戈登的建议是好的,使用WITH语句的替代方法是:

WITH aloc AS (
  SELECT location, SUM(sales) FROM actual GROUP BY 1
), bloc AS (
  SELECT location, SUM(sales) FROM budget GROUP BY 1
)
SELECT location, a.sum AS actual_sales, b.sum AS budget_sales
FROM aloc a LEFT JOIN bloc b USING (location)

这等效于:

SELECT location, a.sum AS actual_sales, b.sum AS budget_sales
FROM (SELECT location, SUM(sales) FROM actual GROUP BY 1) a LEFT JOIN
     (SELECT location, SUM(sales) FROM budget GROUP BY 1) b USING (location)

但是我发现WITH语句更具可读性。

子查询的目的是使表进入一种状态,在这种状态下,行意味着一些相关的内容,即aloc在每个位置都包含一行,从而使联接评估您想要的状态。