【问题标题】:TSQL - aggregate function on an expression containing an aggregate ERRORTSQL - 包含聚合错误的表达式上的聚合函数
【发布时间】:2012-02-28 09:26:59
【问题描述】:

您好,我有一个这样的程序:

CREATE PROCEDURE dbo.DWS_PROG (
                                @fromDate datetime = '2012-01-01',
                                @maxMoney money = 200,
                                @limit int = 200 
                              )
AS
SET NOCOUNT ON; 

SELECT TOP (@limit)
     convert(int,P.P_ID) AS 'ID'
    , max(convert(MONEY,isnull(P.NGp,P.NGz))) AS 'NG'
    , max(convert(MONEY,(CASE WHEN D.Doc_Type = 0x0000000000000016 
                              THEN Cash_PLN 
                              ELSE 0 END))) AS 'Interests'
    , (SELECT TOP 1 convert(VARCHAR, H.Data_zmiany,105) 
         FROM dbo.Pozew_Historia_Stanow H 
        WHERE  H.P_ID = P.P_ID 
          AND H.Stan_nastepny_id = 0x000000000000000D /*PZ*/) AS 'Data Pozwu'
    , max((CASE WHEN Sad_Id=0x0000000000000E08 
                THEN 'EL' 
                ELSE 'PA' END)) AS 'TYPE'
    , max((CASE WHEN Cost_Name =0x0000000000000008 
                THEN convert(varchar, Pay_Date,105) 
                ELSE NULL END)) AS 'Data pierwszego kosztu wpisu sądowego'
    , (SELECT TOP 1 convert(VARCHAR, H.Data_zmiany,105) 
         FROM dbo.Pozew_Historia_Stanow H 
        WHERE H.P_ID = P.P_ID 
          AND H.Stan_nastepny_id = 0x00000000000000DD /*EGZ-1*/) AS 'Data wszczęcia egzekucji'
    , sum((CASE WHEN D.Doc_Type = 0x0000000000000003 
                 AND D.Pay_Date >= @fromDate 
                 AND D.Pay_Date < DATEADD(mm,DATEDIFF(mm,0,@fromDate) + 1,0) 
                THEN Cash_PLN 
                ELSE 0 END)) AS 'M0'
 FROM dbo.Pozew P 
 JOIN dbo.Orders  Z 
   ON Z.Orders_Id = P.Orders_Id 
 JOIN dbo.Docs D 
   ON D.P_ID = P.P_ID
WHERE ((P.NGp IS NOT NULL AND P.NGp < @maxMoney) OR (P.NGp IS NULL AND P.NGz < @maxMoney))
  AND P.Stan IN ('PZ-PORAŻKA','PZ-PORAŻ-UB','PZ-PSPPOR-SP','PZ-PSPPOR-UP','PZ-PSSSUK-UP','PZ-ZAPŁATA','EGZ-C-ROSZ-1','EGZ-C-ROSZ-2','EGZ-SUKCES-S','EGZ-ZAS-R','EGZ-NZAS-R','EGZ-BS-1C','EGZ-WSZP-1','EGZ-WSZP-2','EGZ-SPL')
  AND (SELECT TOP 1 dbo.Docs.Pay_Date 
         FROM dbo.Docs 
        WHERE dbo.Docs.P_ID = P.P_ID 
          AND dbo.Docs.Cost_Name = 0x0000000000000008 
     ORDER BY dbo.Docs.Pay_Date) >= @fromDate
GROUP BY P.P_ID

这基本上可以正常工作,但我有一个错误。 在 JOIN 之前的最后一行中,我为所有类型为 0x00...03 且 Pay_date 介于 @param 和 param 的月末之间的文档汇总现金。简单有效:)

但我必须用子查询替换@fromDate:

SELECT TOP 1 dbo.Docs.Pay_Date 
  FROM dbo.Docs 
 WHERE dbo.Docs.P_ID = P.P_ID 
   AND dbo.Docs.Cost_Name = 0x0000000000000008 
   AND dbo.Docs.Pay_Date >= @fromDate  
 ORDER BY dbo.Docs.Pay_Date

因此,对于每个文档查询,都将采用特定付款类型的第一个日期,然后将从该日期开始到月底的所有付款相加。

SUM 应如下所示:

SUM((CASE WHEN D.Doc_Type = 0x0000000000000003 
           AND D.Pay_Date >= 
               (SELECT TOP 1 dbo.Docs.Pay_Date 
                  FROM dbo.Docs 
                 WHERE dbo.Docs.P_ID = P.P_ID 
                   AND dbo.Docs.Cost_Name = 0x0000000000000008 
                   AND dbo.Docs.Pay_Date >= @fromDate  
                 ORDER BY dbo.Docs.Pay_Date)

           AND D.Pay_Date < DATEADD(mm, DATEDIFF(mm, 0, 
              (SELECT TOP 1 dbo.Docs.Pay_Date 
                 FROM dbo.Docs 
                WHERE dbo.Docs.P_ID = P.P_ID 
                  AND dbo.Docs.Cost_Name = 0x0000000000000008 
                  AND dbo.Docs.Pay_Date >= @fromDate 
                ORDER BY dbo.Docs.Pay_Date)) + 1,0) 
         THEN Cash_PLN 
         ELSE 0 END)) AS 'M0'

但在这样做之后,Management Studio 会引发错误:

无法对包含聚合或子查询的表达式执行聚合函数。

我试图解决这个问题将近 2 天。 有什么想法吗?

抱歉没有显示表的结构,但是数据库太大了,我只需要一个方法来解决这个错误:)

我的表格如下所示: 表 Pozew:id、name 等

表文档:docid、p_id(来自 Pozew 表的键)、doc_type、cost_name、pay_date、cash_PLN

示例记录如下所示:

文档:

1,1,15,8,'2011-02-04',400
1,1, 3,5,'2011-02-09',0
1,1, 3,5,'2011-02-12',0
1,1, 3,5,'2011-02-04',0

简单场景: 我们在 docs 表中添加一条记录,说明我们有第 1 个文档,cost_name=0x8,然后添加其他文档,但 Doc_Type = 0x3。

因此,我们希望获取所有 doc_Type =0x3 并且在 cost_name=0x8 的第一个文档的创建日期和月末之间添加的所有文档。 但是我们必须为每个 Pozew_id 对它们进行分组。

对不起,我的英语倒了:/

我创建了一个简单的查询,可以更清楚地显示我的问题:

DECLARE @fromDate varchar
SET @fromDate = '2011-06-01'
SELECT TOP 100
sum((CASE WHEN D.Typ_dokumentu = 0x0000000000000003 
          AND D.Data_platnosci >= 
          (SELECT TOP 1 Data_platnosci
           FROM Dokumenty
           WHERE Pozew_Id = P.Pozew_Id 
           AND Nazwa_kosztu = 0x0000000000000008
           AND Data_platnosci >= @fromDate 
           GROUP BY Pozew_Id) 
          AND Data_platnosci < DATEADD(mm,DATEDIFF(mm,0,
          (SELECT TOP 1 Data_platnosci 
           FROM Dokumenty 
           WHERE Pozew_Id = P.Pozew_Id
           AND Nazwa_kosztu = 0x0000000000000008
           AND Data_platnosci >= @fromDate
           GROUP BY Pozew_Id)
           ) + 1,0) THEN Kwota_PLN ELSE 0 END)) AS 'M0'
FROM
Dokumenty D
JOIN Pozew P
    ON D.Pozew_Id = P.Pozew_Id
WHERE
((P.NGp IS NOT NULL
AND
P.NGp < 200)
OR
(P.NGp IS NULL
AND
P.NGz < 200))
AND
P.Stan IN ('PZ-PORAŻKA','PZ-PORAŻ-UB','PZ-PSPPOR-SP')
AND
(SELECT TOP 1
     dbo.Dokumenty.Data_platnosci
 FROM
     dbo.Dokumenty
 WHERE
     dbo.Dokumenty.Pozew_Id = P.Pozew_Id
     AND
     dbo.Dokumenty.Nazwa_kosztu = 0x0000000000000008
 ORDER BY
     dbo.Dokumenty.Data_platnosci) >= @fromDate

【问题讨论】:

  • 抱歉@Filip De Vos 格式混乱:/
  • 不用担心。在 vim 中的 gg=G 上。

标签: sql-server tsql aggregate-functions


【解决方案1】:

难道不可能在您的联接中有一个派生表来提供“@fromDate 之后每种付款类型的第一个”,然后在您的选择语句中与之进行比较。

即派生查询类似于

select p_id, min(pay_date) startDate  
from docs 
where cost_name = 0x0000000000000008 
  and pay_date >= @fromDate 
group by p_id 
order by pay_date

您按付款类型加入派生表,从而获得适当的开始日期。

那么你的总和是:

sum((case when d.doc_type = 0x0000000000000003 
           and d.pay_date >= startDate 
           and month(d.pay_date) = month(startDate) 
           and year(d.pay_date) = year(startDate)) then cash_pln 
          else 0 end) as 'M0'

注意我没有尝试过,所以它可能不完全正确,但希望它显示了原理

【讨论】:

  • 我已经对包含您的查询记录的表进行了另一次联接。它就像一个魅力:)
  • 伪 SQL 是前进的方向!谢谢
【解决方案2】:

我会将 pay_date 放入一个变量并使用它。毕竟是一个常数值。

DECLARE @pay_date datetime
SET @pay_date = (SELECT TOP 1 dbo.Docs.Pay_Date 
                   FROM dbo.Docs 
                  WHERE dbo.Docs.P_ID = P.P_ID 
                    AND dbo.Docs.Cost_Name = 0x0000000000000008 
                    AND dbo.Docs.Pay_Date >= @fromDate  
                  ORDER BY dbo.Docs.Pay_Date)

然后在您的查询中

  AND D.Pay_Date >= @pay_date

【讨论】:

  • 感谢您的回答,但是(对不起,如果这听起来很愚蠢)如果我声明一个变量并像上面一样使用它,我的所有记录的 pay_date 都会大于@pay_date。我需要做的是为每个文档选择 pay_date。我将编辑我的帖子以显示我想要完成什么样的逻辑:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
  • 1970-01-01
  • 1970-01-01
  • 2016-08-02
  • 1970-01-01
相关资源
最近更新 更多