如何将WHERE子句与PIVOT一起使用

时间:2014-02-19 15:01:29

标签: sql sql-server tsql sql-server-2008-r2 pivot

为什么,这里我的where子句被忽略了,无论作为参数输入的值是什么,它总结发票,花费数小时就疯了!

ALTER PROCEDURE [dbo].[Usp_custom_dash_metric_invoicespend] 
  @CompanyGUID  UNIQUEIDENTIFIER, 
  @UserGUID UNIQUEIDENTIFIER, 
  @CompanyUserGUID UNIQUEIDENTIFIER, 
  @InvoiceYearFrom CHAR(4), 
  @InvoiceYearTo CHAR(4), 
  @CompanySupplierGUID UNIQUEIDENTIFIER 
AS 
BEGIN 
 WITH _d 
   AS (SELECT a.totalgrossvaluehome1 AS tgvh1, 
              invoicedate            AS ind, 
              c.guid                 AS cug, 
              a.companysupplierguid  AS cus, 
              c.userguid             AS ug, 
              b.guid                 AS cg 
       FROM   invoices a (nolock) 
              JOIN companies b (nolock) 
                ON ( a.companyguid = b.guid ) 
              JOIN companyusers c (nolock) 
                ON ( c.userguid = a.createdbyguid ) 
       WHERE  a.invoicedate BETWEEN Cast(Isnull(NULL, Cast(Datepart(year 
                                         , 
                                         Dateadd( 
                                         year, -1, 
                                                 Getdate()))AS NVARCHAR( 
                                         max 
                                         ))) 
                                         + '-01-01' AS DATETIME) AND 
                                    Cast( 
              Isnull(NULL, Cast(Datepart(year, 
              Getdate() 
              )AS 
              NVARCHAR(max))) 
              + '-12-31' AS DATETIME) 
              AND c.guid = @CompanyUserGUID 
               OR @CompanyUserGUID IS NULL 
                  AND a.companysupplierguid = @CompanySupplierGUID 
               OR @CompanySupplierGUID IS NULL 
                  AND c.userguid = @UserGUID 
               OR @UserGUID IS NULL 
                  AND a.companyguid = @CompanyGUID 
               OR @CompanyGUID IS NULL) 
SELECT * 
FROM   (SELECT Year(ind)                    AS [ayear], 
             LEFT(Datename(month, ind), 3)AS [amonth], 
             Isnull(tgvh1, 0)             AS Amount 
      FROM   _d 
      WHERE  cug = @CompanyUserGUID 
              OR @CompanyUserGUID IS NULL 
                 AND cus = @CompanySupplierGUID 
              OR @CompanySupplierGUID IS NULL 
                 AND ug = @UserGUID 
              OR @UserGUID IS NULL 
                 AND cg = @CompanyGUID 
              OR @CompanyGUID IS NULL)s 
     PIVOT ( Sum(amount) 
           FOR [amonth] IN (jan, 
                            feb, 
                            mar, 
                            apr, 
                            may, 
                            jun, 
                            jul, 
                            aug, 
                            sep, 
                            oct, 
                            nov, 
                            dec) )AS pivotal 
WHERE  pivotal.ayear >= Isnull(@InvoiceYearFrom, Datepart(year, 
                                               Dateadd(year, -1, 
                                                      Getdate() 
                                               ))) 
     AND pivotal.ayear <= Isnull(@InvoiceYearTo, Datepart(year, Getdate( 
                                                 )) 
                          ) 
ORDER  BY [ayear] 
END   

具体来说:

WHERE  a.invoicedate BETWEEN Cast(Isnull(@InvoiceDateFrom, Cast(Datepart(year 
                                         , 
                                         Dateadd( 
                                         year, -1, 
                                                 Getdate()))AS NVARCHAR( 
                                         max 
                                         ))) 
                                         + '-01-01' AS DATETIME) AND 
                                    Cast( 
              Isnull(@InvoiceDateTo, Cast(Datepart(year, 
              Getdate() 
              )AS 
              NVARCHAR(max))) 
              + '-12-31' AS DATETIME) 
              AND c.guid = @CompanyUserGUID 
               OR @CompanyUserGUID IS NULL 
                  AND a.companysupplierguid = @CompanySupplierGUID 
               OR @CompanySupplierGUID IS NULL 
                  AND c.userguid = @UserGUID 
               OR @UserGUID IS NULL 
                  AND a.companyguid = @CompanyGUID 
               OR @CompanyGUID IS NULL) 

例如,数据库中返回的数据是对所有数据求和(我假设是因为它从CTX获取的数据包含过滤后的数据,所以我希望如果我传入@Userguid =(一个真实的用户ID)它会将转动的计数限制为仅供用户使用的发票...它不会:&#39;(

2 个答案:

答案 0 :(得分:1)

查看您的WHERE子句,我看到OR用于未分组语句。我想你想用以下内容替换你WHERE子句的最后一个部分(注意你需要一个额外的结束时间来结束你的CTE):

AND (c.guid = @CompanyUserGUID    -- Added opening paren (required)
 OR (@CompanyUserGUID IS NULL     -- Added parens around group (optional)
    AND a.companysupplierguid = @CompanySupplierGUID)
 OR (@CompanySupplierGUID IS NULL -- Added parens around group (optional)
    AND c.userguid = @UserGUID)
 OR (@UserGUID IS NULL            -- Added parens around group (optional)
    AND a.companyguid = @CompanyGUID)
 OR @CompanyGUID IS NULL)         -- Added closing paren

<强>更新

更仔细地查看WHERE子句的内容,我想您可能想要添加一堆额外的分组。据我所知,我认为如果所有以前的 GUID参数都是NULL,您的意图是仅检查GUID参数。您当前的WHERE子句检查所有GUID参数,其中前一个(但不一定是之前的那个)是NULL。这些分组应该解决这个问题。

AND (c.guid = @CompanyUserGUID
    OR (   @CompanyUserGUID IS NULL
       AND (a.companysupplierguid = @CompanySupplierGUID
           OR (   @CompanySupplierGUID IS NULL
              AND (c.userguid = @UserGUID
                  OR (   @UserGUID IS NULL
                     AND (  a.companyguid = @CompanyGUID
                         OR @CompanyGUID IS NULL))))))))

结束更新

据我了解SQL-Server中的操作顺序,不需要围绕单个@param IS NULL OR column = @param子句的括号(除了使您的意图更清晰)。 另一方面,整个分组的开括号和右括号是必要的。没有它,你的SQL正在检查(a.invoicedate BETWEEN ... AND c.guid = @CompanyUserGUID) OR [GUID clauses...]

此外,我强烈建议您清理获取时间范围的SQL。您可以使用以下内容简化它们(并使代码更易于阅读和诊断):

-- "Start of last year":
--     Get the number of years from 0 (1900-01-01) to this year from 0
--     Then add add that many years (minus 1 for last year) back to 0
DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE())-1, 0)
-- "End of this year": Get "the start of next year" and subtract one day
DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE())+1, 0))

请注意,除非您的invoicedate列截断时间,否则由于过滤器中的时间戳为00:00:00,您当前的逻辑实际上会排除2014-12-31的记录。如果是这种情况,我建议你去明年年初。

答案 1 :(得分:1)

我认为你应该在这里添加适当的括号,将OR&amp;组合在一起。 AND条件很重要

AND c.guid = @CompanyUserGUID 
OR @CompanyUserGUID IS NULL 
 AND a.companysupplierguid = @CompanySupplierGUID 
  OR @CompanySupplierGUID IS NULL 
              AND c.userguid = @UserGUID 
           OR @UserGUID IS NULL 
              AND a.companyguid = @CompanyGUID 
           OR @CompanyGUID IS NULL