为啥这个查询不能正常工作?

Posted

技术标签:

【中文标题】为啥这个查询不能正常工作?【英文标题】:why won't this query work properly?为什么这个查询不能正常工作? 【发布时间】:2014-03-30 08:58:23 【问题描述】:

我的MasterSales 表是这样的

SalesDate | Category | Total
----------------------------- 
1/1/2000    01          100 
1/1/2000    02          110
1/2/2000    01          80
1/2/2000    03          20

我的Category 表看起来像这样

ID | Name
----------
01 | A
02 | B
03 | C
04 | D

我的查询如下所示:

SELECT m.SalesDate, c.Name, SUM(ISNULL(m.Total,0)) AS TotalSales
FROM MasterSales m
LEFT JOIN Category c ON c.ID = m.Category
WHERE m.SalesDate BETWEEN '1/1/2000' AND '1/2/2000'

我想要的结果是这样的:

SalesDate | Name | TotalSales
------------------------------
1/1/2000    A      100
1/1/2000    B      110
1/1/2000    C      0
1/1/2000    D      0
1/2/2000    A      80
1/2/2000    B      0
1/2/2000    C      20
1/2/2000    D      0

但我得到的结果是这样的:

SalesDate | Name | TotalSales
------------------------------
1/1/2000    A      100
1/1/2000    B      110
1/2/2000    A      80
1/2/2000    C      20

我已经尝试使用RIGHT JOIN 而不是LEFT JOIN 并在FROM 子句上切换表,但结果仍然相同。谁能帮我解释一下为什么它不能正常工作?

附: : 我使用的是 SQL Server 2005(如果重要的话)

【问题讨论】:

在查询末尾添加GROUP BY m.SalesDate, c.Name 这里的逻辑是什么? 01012000 和 01022000 类 D 的销售日期如何获得? 您加入条件c.ID = m.Category,所以很明显Name=D 不会被选中,因为id=4 在其他表中不可用 @TinTran:我也试过了,但结果是一样的。@SatheeshVariath Variath:我在查询中使用Between@Gone:我想通过使用left join Category所有数据即使另一个表中没有匹配项,来自Category 也会出现?顺便说一句,如何在评论中添加断线? 非常感谢所有试图提供帮助的人。我选择了 Darka 的答案,因为它是在 management studio 上尝试的最简单的答案,而且效果很好(不是其他人都错了,我只是没有全部尝试):D 【参考方案1】:

这是我的答案

WITH MasterSales (SalesDate, Category, Total) AS (
  SELECT       '1/1/2000','01',100
  UNION SELECT '1/1/2000','02',110
  UNION SELECT '1/2/2000','01',80
  UNION SELECT '1/2/2000','03',20
), Category (ID, Name) AS (
  SELECT       '01','A'
  UNION SELECT '02','B'
  UNION SELECT '03','C'
  UNION SELECT '04','D'
), getDates AS (
  SELECT DISTINCT SalesDate 
  FROM MasterSales 
  WHERE SalesDate BETWEEN '1/1/2000' AND '1/2/2000'
)

SELECT gD.SalesDate, C.Name, SUM(ISNULL(MS.Total,0)) AS TotalSales
FROM getDates AS gD
CROSS JOIN Category AS C
LEFT JOIN MasterSales AS MS 
    ON MS.Category = C.ID
    AND MS.SalesDate = gD.SalesDate 
GROUP BY gD.SalesDate, C.Name

【讨论】:

我不认为这对所有这些静态值都有好处 你在哪里看到静态的??它只是 cte 的示例;)【参考方案2】:

试试这个。这涵盖了您拥有 MasterSales 的所有日期。换句话说,这填补了当天缺失的类别。但是,您还想填写缺失的日期,您需要创建一个日期控制表。查看日期表的recursive cte

;with control_table as (
  select distinct SalesDate, ID
  from MasterSales ms
  cross join Category c
  where ms.SalesDate between '1/1/2000' AND '1/2/2000'
  )


select ct.SalesDate, c.Name as Category, coalesce(sum(ms.Total),0) as Total
from control_table ct
inner join Category c
  on ct.ID = c.ID
left join MasterSales ms
  on ct.SalesDate = ms.SalesDate
  and ct.ID = ms.Category
group by ct.SalesDate, c.Name
order by ct.SalesDate asc, c.Name asc

FIDDLE

【讨论】:

这几乎比我的要好 - 你忘了SUM @Alexander,谢谢,添加总和【参考方案3】:

你的问题终于解决了。使用这个查询:

SELECT AAA.SalesDate,AAA.Name,ISNULL(BBB.TotalSales,0) as TotalSales  
FROM (
    (SELECT m.SalesDate, c.Name
    FROM MasterSales m,Category c
    WHERE m.SalesDate BETWEEN '1/1/2000' AND '1/2/2000'
    GROUP BY m.SalesDate,c.Name) AAA

    LEFT JOIN 

    (SELECT m.SalesDate,c.Name, SUM(ISNULL(m.Total,0)) AS TotalSales
    FROM MasterSales m,Category c
    WHERE m.SalesDate BETWEEN '1/1/2000' AND '1/2/2000'
    AND c.ID=m.Category 
    GROUP BY m.SalesDate,c.Name) BBB 
    on AAA.SalesDate=BBB.SalesDate AND AAA.Name=BBB.Name) 

说明:

查询的第一部分 (AAA) 选择 SalesDateCategory 的所有组合。

查询的第二部分 (BBB) 选择 SalesDateCategoryTotalSales

然后我们通过SalesDateCategory 加入他们(AAA 和 BBB)。

完美运行!!!。见SQL Fiddle

【讨论】:

我怀疑这将失去我或 sam yi 解决方案的性能【参考方案4】:

更新:更改了使用sam yi logic创建临时表的方法

我建议你创建一个加法表。

;WITH control_table AS (
      SELECT DISTINCT SalesDate, Name
        FROM MasterSales ms
             CROSS JOIN Category c
       )

SELECT d.SalesDate,
       c.name,
       COALESCE(sum(m.total),0) totalsales
  FROM control_table d
       LEFT OUTER JOIN Category c
            ON d.Name = c.name
       LEFT OUTER JOIN MasterSales m
            ON (c.id = m.category
                AND d.SalesDate = m.salesdate)
WHERE d.SalesDate BETWEEN '1/1/2000' 
                      AND '1/2/2000'
GROUP BY 
       d.SalesDate,
       c.name
ORDER BY 
       d.SalesDate,
       c.name;

Here is SQLFiddle

【讨论】:

创建另一个表并将所有数据插入其中?我认为这不是一个好主意。【参考方案5】:
SELECT cj.Date, cj.Name, IsNull(m.Total,0) Total
FROM (SELECT d.Date, c.Name, c.Id
    FROM (SELECT DISTINCT SalesDate Date 
          FROM MasterSales) d, Category c) cj
LEFT JOIN MasterSales m ON m.SalesDate = cj.Date 
  AND cj.Id = m.Category

http://www.sqlfiddle.com/#!3/d1344/3

添加您的日期间隔条件

而且我确信有更好的方法来做到这一点。

干杯

【讨论】:

为什么是负面的?你试过吗? :(

以上是关于为啥这个查询不能正常工作?的主要内容,如果未能解决你的问题,请参考以下文章

为啥这个java程序不能正常工作?

为啥这个 HTML 表格在 Chrome 中不能正常工作?

为啥这个python中最大的主要因素的代码不能正常工作

为啥这个使用Combiner 类的Hadoop 示例不能正常工作? (不要执行Combiner提供的“局部缩减”)

为啥这个 c++ 代码在 Linux 中可以正常工作,但在 Windows 中却不能[关闭]

为啥 Canvas.SetTop 动画不能正常工作?