子查询T-SQL中的GROUP BY

时间:2013-11-11 04:00:16

标签: sql-server tsql group-by subquery

我正在尝试制作一个这样的表:

  

产品名称| SalesByDate | TotalSalesUntilDate

    A     |      5    |      15

    B     |     10    |      30

    C     |     20    |      25

    D     |     18    |      43

SalesByDate表示在输入日期为每种产品销售的产品数量,TotalSalesUntilDate表示从每月的第一个日期到输入日期的每种产品的销售产品数量(输入日期的示例:2010年3月17日)< / p>

我使用子查询编写了这个查询:

    select p.ProductName, A.SalesByDate,
      (select(SUM(case when (pd.Date between '01' and @Date) 
      then s.SalesByDate else 0 end)) 
    from Period pd 
    inner join Sales s on pd.TimeID = s.TimeID 
    full join Product p on s.ProductID = p.ProductID) as TotalSalesUntilDate 
    from Product p join 
         (select s.ProductID, pd.Date, s.SalesByDate
          from Period pd join Sales s on pd.TimeID = s.TimeID) A on 
    p.ProductID = A.ProductID where @Date = A.Date

但我得到了结果:

  

产品名称| SalesByDate | TotalSalesUntilDate

     A    |     5     |      113

     B    |    10     |      113

     C    |    20     |      113

     D    |    18     |      113

其中TotalSalesUntilDate显示从月份的第一个日期到输入日期之间销售的产品数量,但是对于每个产品没有分离的所有产品。

所以,当我尝试将查询更改为这样时(在“作为TotalSalesUntilDate”之前添加GROUP BY p.ProductID):

   select p.ProductName, A.SalesByDate,
     (select(SUM(case when (pd.Date between '01' and @Date) 
     then s.SalesByDate else 0 end)) 
   from Period pd 
     inner join Sales s on pd.TimeID = s.TimeID 
     full join Product p on s.ProductID = p.ProductID 
     group by p.ProductID) as TotalSalesUntilDate 
  from Product p join 
     (select s.ProductID, pd.Date, s.SalesByDate
     from Period pd join Sales s on pd.TimeID = s.TimeID) A on 
    p.ProductID = A.ProductID where @Date = A.Date

当我执行此查询时,收到此错误消息:

  

“消息512,级别16,状态1,过程SalesMTDSubQuery,第7行   子查询返回的值超过1。这是不允许的   子查询跟随=,!=,&lt;,&lt; =,&gt;,&gt; =或当子查询用作   表达。“

由于我是SQL新手并且还在学习,但我不明白如何解决这个问题。任何帮助将不胜感激。谢谢。

2 个答案:

答案 0 :(得分:3)

@Date变量中,我们存储日期:

SELECT DISTINCT PT.[ProductName]
      ,SUM(IIF(PD.[Date] = @Date, SL.[SalesByDate], 0)) 
      ,SUM(IIF(PD.[Date] BETWEEN '01' AND @Date, SL.[SalesByDate], 0)) 
FROM @Product PT
INNER JOIN @Sales SL
    ON PT.[ProductID] = SL.[ProductID]
INNER JOIN @Period PD
    ON SL.[TimeID] = PD.[TimeID]
GROUP BY PT.[ProductName]

结果:

enter image description here

完整代码:

DECLARE @Period TABLE
(
     [TimeID] TINYINT
    ,[Date] CHAR(2)
)

INSERT INTO @Period([TimeID], [Date])
VALUES   (1,'01')
        ,(2,'02')
        ,(3,'03')
        ,(4,'04')
        ,(5,'05')
        ,(6,'06')
        ,(7,'07')
        ,(8,'08')
        ,(9,'09')
        ,(10,'10')
        ,(11,'11')
        ,(12,'12')
        ,(13,'13')
        ,(14,'14')
        ,(15,'15')

DECLARE @Product TABLE
(
     [ProductID] TINYINT
    ,[ProductName] CHAR(1)
)

INSERT INTO @Product( [ProductID], [ProductName])
VALUES (1,'A')
      ,(2,'B')
      ,(3,'C')
      ,(4,'D')

DECLARE @Sales TABLE
(
     [TimeID] TINYINT
    ,[ProductID] TINYINT
    ,[SalesByDate] TINYINT
)

INSERT INTO @Sales ([TimeID], [ProductID], [SalesByDate])
VALUES   (1, 1, 10)
        ,(1, 4, 20)
        ,(7, 2, 10)
        ,(7, 3, 5)
        ,(15, 1, 5)
        ,(15, 2, 10)
        ,(15, 3, 15)
        ,(15, 4, 18)
        ,(19, 2, 15)
        ,(20, 3, 2)
        ,(22, NULL, 2)
        ,(1, 4, 5)
        ,(7, 2, 10)
        ,(15, 3, 5)

DECLARE @Date CHAR(2) = '15'

SELECT DISTINCT PT.[ProductName]
      ,SUM(IIF(PD.[Date] = @Date, SL.[SalesByDate], 0)) 
      ,SUM(IIF(PD.[Date] BETWEEN '01' AND @Date, SL.[SalesByDate], 0)) 
FROM @Product PT
INNER JOIN @Sales SL
    ON PT.[ProductID] = SL.[ProductID]
INNER JOIN @Period PD
    ON SL.[TimeID] = PD.[TimeID]
GROUP BY PT.[ProductName]

编辑:

如果您需要使用子查询,这就是您的示例的工作方式:

SELECT PT.[ProductName]
      ,SUM(SL.[SalesByDate])
      ,DataSource.[TotalSalesByDate]
FROM @Product PT
INNER JOIN @Sales SL
    ON PT.[ProductID] = SL.[ProductID]
INNER JOIN @Period PD
    ON SL.[TimeID] = PD.[TimeID]
INNER JOIN 
(
    SELECT S.[ProductID]
          ,SUM(S.[SalesByDate]) AS [TotalSalesByDate]
    FROM @Sales S
    INNER JOIN @Period P
        ON S.[TimeID] = P.[TimeID]
    WHERE P.[Date] BETWEEN '01' AND @Date 
    GROUP BY S.[ProductID] 
) AS DataSource
ON PT.[ProductID] = DataSource.[ProductID]
WHERE PD.[Date] = @Date
GROUP BY PT.[ProductName]
     ,DataSource.[TotalSalesByDate]

答案 1 :(得分:1)

首先,在Table Period中,您必须有日期,而不是'01','02',因此您可以使用BETWEEN。或者你可以使用1,2,3 ...,但它们必须是数字。

因此,我们假设在表Table Period中您有日期数字(我发表此评论,因为您使用01,而不是1,它假设字符串值。查询本身相对容易:

SELECT 
  p.ProductName, 
  SUM(CASE WHEN s.TimeID = 10 THEN s.SalesByDate ELSE 0 END) as SalesByDate, 
  SUM(CASE WHEN s.TimeID = 10 THEN 0 ELSE s.SalesByDate END) as TotalSalesUntilDate 
FROM 
  Product p 
  INNER JOIN Salse s ON p.ProductID = s.ProductID 
WHERE 
  s.TimeID BETWEEN 1 AND 10
GROUP BY p.ProductName;

您为每个日期获取销售额。如果这是选定日期,则将销售额添加到列SalesByDate,否则添加到列TotalSalesUntilDate。您按ProductName分组以计算SUM。并在WHERE子句中仅选择所需期间的日期。我们假设此查询仅在特定月份启动(因为我们仅使用日期元素 - 即1,2,......而不是月份)。

这将仅显示具有销售额的产品。如果您想查看所有产品列表,请使用LEFT JOIN代替INNER JOIN