在MySQL中,如何使用表A以一对多的关系连接两个表?
我有两张桌子 “存储”表是一个人口统计表,包含如下字段: ID、ParentID、ConsolidationType ID是给定存储的唯一标识符 如果父存储的ConsolidationType为“Secondary”,则ParentID可以为NULL,也可以包含父存储的ID ConsolidationType为NULL、“主要”或“次要” “Sales”表包含如下字段: StoreID、SalesDate、SalesAmount StoreID是指Store表中的ID 我试图在单个查询的一行中获取给定商店的总合并销售额和个人销售额。我编写了如下所示的SQL查询:在MySQL中,如何使用表A以一对多的关系连接两个表?,mysql,left-join,one-to-many,Mysql,Left Join,One To Many,我有两张桌子 “存储”表是一个人口统计表,包含如下字段: ID、ParentID、ConsolidationType ID是给定存储的唯一标识符 如果父存储的ConsolidationType为“Secondary”,则ParentID可以为NULL,也可以包含父存储的ID ConsolidationType为NULL、“主要”或“次要” “Sales”表包含如下字段: StoreID、SalesDate、SalesAmount StoreID是指Store表中的ID 我试图在单个查询的一行中获
SELECT
Store.ID AS 'Store ID',
SUM(IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)) AS 'Individual Sales',
SUM(IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1 AND YEAR(secondaries.SalesDate) = 2012 AND QUARTER(secondaries.SalesDate) = 1,main.SalesAmount + secondaries.SalesAmount,0) AS 'Consolidated Sales'
FROM Store
LEFT JOIN Sales AS 'main' ON Store.ID = main.StoreID
LEFT JOIN Sales AS 'secondaries' ON Store.ParentID = secondaries.StoreID
GROUP BY Store.ID
我不明白这为什么不能按预期工作。我错过了什么?我的逻辑出了什么问题?问题是,您的查询正在生成类似笛卡尔乘积的结果集 基本上,“main”中的一行对于“secondaries”中的每个匹配行重复多次 要获得所需的结果,只需连接到sales表一次,并匹配StoreID和ParentID 要获取单个销售,请仅在StoreID匹配的总和行中包括,如下所示:
SELECT Store.ID AS `Store ID`
, SUM(IF(main.StoreID = Store.ID,
IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)
,0)) AS `Individual Sales`
, SUM(
IF(YEAR(main.SalesDate) = 2012 AND QUARTER(main.SalesDate) = 1,main.SalesAmount,0)
) AS `Consolidated Sales`
FROM Store
LEFT JOIN Sales AS `main` ON main.StoreID = Store.ID OR main.StoreID = Store.ParentID
GROUP BY Store.ID
更新
我的错。啊!ParentID在Store表上,而不是Sales表上
上面的查询不返回指定的结果。正在努力
我想你已经有了解决办法
使用ParentID列代替Store表中的ID列。
如果ParentID列为NULL,则使用ID列中的值
此查询返回指定的结果集:
SELECT t.StoreID AS `Store ID`
, SUM(IF(t.source='p',
IF(YEAR(t.SalesDate) = 2012 AND QUARTER(t.SalesDate) = 1,t.SalesAmount,0)
,0)) AS `Individual Sales`
, SUM(
IF(YEAR(t.SalesDate) = 2012 AND QUARTER(t.SalesDate) = 1,t.SalesAmount,0)
) AS `Consolodiated Sales`
FROM (
SELECT 'p' AS source
, a.StoreID
, a.SalesDate
, a.SalesAmount
FROM Sales a
UNION ALL
SELECT 's' AS source
, s.ParentID
, b.SalesDate
, b.SalesAmount
FROM Sales b
JOIN Store s ON s.ID = b.StoreID
WHERE s.ParentID IS NOT NULL
) t
GROUP BY t.StoreID
ORDER BY t.StoreID
这不是最有效的,内联视图或派生表的大小取决于Sales表的大小。将日期上的谓词向下推送到内联视图中,或者在派生表中按月份或季度汇总,效率会更高
我更可能将季度作为结果集的一部分返回,以允许我提取多个季度
SELECT t.StoreID AS `Store ID`
, t.SalesQuarter
, SUM(IF(t.source='p',t.SalesAmount,0)) AS `Individual Sales`
, SUM(t.SalesAmount) AS `Consolodiated Sales`
FROM (
SELECT 'p' AS source
, a.StoreID
, ADDDATE(MAKEDATE(YEAR(a.SalesDate),1), INTERVAL FLOOR(MONTH(a.SalesDate)/4) QUARTER) AS SalesQuarter
, SUM(a.SalesAmount) AS SalesAmount
FROM Sales a
-- WHERE a.SalesDate >= '2012-01-01'
-- AND a.SalesDate < '2012-04-01'
GROUP BY a.StoreID, SalesQuarter
UNION ALL
SELECT 's' AS source
, s.ParentID
, ADDDATE(MAKEDATE(YEAR(b.SalesDate),1), INTERVAL FLOOR(MONTH(b.SalesDate)/4) QUARTER) AS SalesQuarter
, SUM(b.SalesAmount) AS SalesAmount
FROM Sales b
JOIN Store s ON s.ID = b.StoreID
WHERE s.ParentID IS NOT NULL
-- AND a.SalesDate >= '2012-01-01'
-- AND a.SalesDate < '2012-04-01'
GROUP BY s.ParentID, SalesQuarter
) t
GROUP BY t.StoreID, t.SalesQuarter
ORDER BY t.StoreID, t.SalesQuarter
我通常尝试将过滤逻辑保留在WHERE子句中。原始查询可能有太多的联接,并且没有子查询的情况可能无法满足您的期望。下面WHERE中的IS NULL检查允许没有子项的存储
SELECT
s.ID
, SUM(s.SalesAmount) AS `Individual Sales`
, SUM(s.SalesAmount) + SUM(c.SalesAmount) AS `Consolidated Sales`
FROM Store AS s
LEFT OUTER JOIN Store AS c ON c.ParentID = s.ID
WHERE YEAR(s.SalesDate) = 2012 AND QUARTER(s.SalesDate) = 1
AND (c.SalesDate IS NULL OR
(YEAR(c.SalesDate) = 2012 AND QUARTER(c.SalesDate) = 1))
GROUP BY s.ID
这就更近了,谢谢你!然而,这里的新问题是,它只能找到“二级”存储行的真正合并总数;“Primary”商店的ParentID为空,在合并列中只有自己的销售额。要解决这个问题,我只需将父项的ID添加到它自己的ParentID字段中,去掉空值。在我针对单个合并集运行的测试中,在返回的三个存储中,只有一个存储的合并金额是正确的。没有自己销售额的次要商店只在合并字段中返回了主要商店的销售额,而主要商店也只在合并字段中返回了自己的销售额。@Uthr:现在,我明白了问题所在。儿童商店的销售额不包括在内。我会努力把它修好的。ParentID在Store表上,但不在Sales表上。。。
SELECT
s.ID
, SUM(s.SalesAmount) AS `Individual Sales`
, SUM(s.SalesAmount) + SUM(c.SalesAmount) AS `Consolidated Sales`
FROM Store AS s
LEFT OUTER JOIN Store AS c ON c.ParentID = s.ID
WHERE YEAR(s.SalesDate) = 2012 AND QUARTER(s.SalesDate) = 1
AND (c.SalesDate IS NULL OR
(YEAR(c.SalesDate) = 2012 AND QUARTER(c.SalesDate) = 1))
GROUP BY s.ID