在SQL Server 2008中使用Min aggreate函数时,'order'附近的语法不正确

时间:2015-09-11 16:07:58

标签: sql sql-server sql-server-2008

我需要在SQL Server 2008R2中运行以下查询,但它会在查询的最小/最大聚合部分上抛出错误Incorrect Syntax near 'Order'

请注意,PONumber字段是一个字符串,但我们使用min/max来识别works as expected中的第一个和最后一个po以及2012

无论如何这可以解决?

WITH CTE AS
(
    SELECT AuditId, DocMasterId, PoNumber,
        RN_ASC  = ROW_NUMBER() OVER (PARTITION BY DocMasterID 
                                     ORDER BY PoNumber ASC),
        RN_DESC = ROW_NUMBER() OVER (PARTITION BY DocMasterID 
                                     ORDER BY PoNumber DESC),
        CNT = COUNT(*) OVER (PARTITION BY DocMasterID),
        F = MIN(PONumber) OVER (PARTITION BY DocMasterId 
                                ORDER BY PoNumber ASC),
        L = MAX(PONumber) OVER (PARTITION BY DocMasterId 
                                ORDER BY PoNumber ASC)
    FROM dbo.MyTable
    WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND 
          (DocumentType = 'Purchase Order') and docmasterid > 0
)

3 个答案:

答案 0 :(得分:0)

你的逻辑很奇怪。您正在获取列的累积最小值和最大值,该列是用于排序的列。所以:

  • min是总分(每个DocMasterId)。不需要累积分钟。
  • 最大值是当前值(对于每个DocMasterId),它也恰好是当前值周期。不需要累积最大值。

因此,您可以将逻辑重写为:

WITH CTE AS
(
    SELECT AuditId, DocMasterId, PoNumber,
        RN_ASC  = ROW_NUMBER() OVER (PARTITION BY DocMasterID 
                                     ORDER BY PoNumber ASC),
        RN_DESC = ROW_NUMBER() OVER (PARTITION BY DocMasterID 
                                     ORDER BY PoNumber DESC),
        CNT = COUNT(*) OVER (PARTITION BY DocMasterID),
        F = MIN(PONumber) OVER (PARTITION BY DocMasterId)
        L = PoNumber
    FROM dbo.MyTable
    WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND 
          (DocumentType = 'Purchase Order') and docmasterid > 0
)

您可能真的想要:

        F = MIN(PONumber) OVER (PARTITION BY DocMasterId)
        L = PoNumber OVER (PARTITION BY DocMasterId)

但是第一个查询等同于您问题中的查询(好吧,如果PoNumber可能是NULL,那么在这种情况下,我必须更加思考它们是否完全等效)

答案 1 :(得分:0)

使用子查询的以下语句应该是等效的:

WITH myCTE(AuditId, DocMasterId, PoNumber) AS
(
    SELECT AuditId, DocMasterId, PoNumber
    FROM dbo.MyTable
    WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND 
          (DocumentType = 'Purchase Order') and docmasterid > 0
),
CTE AS
(
SELECT AuditId, DocMasterId, PoNumber,
       ROW_NUMBER() OVER (PARTITION BY DocMasterID 
                          ORDER BY PoNumber ASC) AS RN_ASC,
       ROW_NUMBER() OVER (PARTITION BY DocMasterID 
                          ORDER BY PoNumber DESC) AS RN_DESC,
       ( SELECT COUNT(*) FROM myCTE t2 WHERE t2.DocMasterID = t.DocMasterID) AS CNT,
       ( SELECT MIN(PONumber) FROM myCTE  t2 WHERE t2.DocMasterID = t.DocMasterID) AS  F,
       ( SELECT MAX(PONumber) FROM myCTE  t2 WHERE t2.DocMasterID = t.DocMasterID) AS L
FROM myCTE t
)

答案 2 :(得分:0)

这是我们最终用作解决方案的内容。不幸的是,任何试图提供帮助的人都无法提供最终答案,因为我们最终在查询中使用了另一个字段,即AuditId。请注意SQL Server 2012中不需要此字段。

使用AuditId字段允许我们使用最小/最大聚合函数,并使用Partion By作为查询的一部分,而不使用Order By

WITH CTE AS
(
    SELECT AuditId, DocMasterId, PoNumber,
           RN_ASC  = ROW_NUMBER() OVER 
           (PARTITION BY DocMasterID ORDER BY AuditId ASC),
           RN_DESC = ROW_NUMBER() OVER 
           (PARTITION BY DocMasterID ORDER BY AuditId DESC),
           CNT = COUNT(*) OVER (PARTITION BY DocMasterID),
           MIN(AuditId) OVER (PARTITION BY DocMasterId) AS F,
           MAX(AuditId) OVER (PARTITION BY DocMasterId) AS L
     FROM MyTable
     WHERE (PONumber IS NOT NULL) AND (PONumber <> '') AND 
     (DocumentType = 'Purchase Order') and docmasterid > 0
)

然后,我们应用了几个inner join来返回与AuditId关联的PONumber。

我们的审计表中返回的结果随后用于修复我们的实时表中的错误条目,因此确保FirstPO和LastPO确实在我们的审计表中的顺序正确是至关重要的。

SELECT DISTINCT CTE.DocMasterId, A.PONumber AS FirstPO, B.PONumber AS LastPO
FROM CTE
INNER JOIN MyTable A 
  ON CTE.F = A.AuditId  
INNER JOIN MyTable B 
  ON CTE.L = B.AuditId  
WHERE CNT >= 2 and a.PONumber <> B.PONumber
AND (RN_ASC = 1 OR RN_DESC = 1) AND (F <> L)
ORDER BY CTE.DocMasterId;

再次感谢所有人的帮助。非常感谢。