select,where和group by子句中的多个CASE表达式

时间:2016-08-25 05:11:38

标签: sql sql-server stored-procedures

我正在努力解决其中一个难得的问题。我想在sql中使用case来优化SQL存储过程。

ProductMetrics表格如下。此表包含有关产品销售价格和数量的数据,以及产品公司,销售区域,产品名称,市场部门。

表ProductMetrics包含10000多行

ProductMetrics
| Day | CompanyId | RegionId | ProdId | DivId | Quantity | Sale

我们有其他参考表 -

Company(CompanyId, CompanyName), 
Region(RegionId, RegionName),
Product(ProdId, ProductName),
Division(DivId, DivisionName) 

用户可以使用以下查询从此表中获取可读统计信息。

Select m.Day, c.CompanyName, r.RegionName, p.ProductName, d.DivisionName, m.Quantity, m.Sale
from ProductMetrics m
left outer join Company on c.CompanyId = m.CompanyId
left outer join Region on r.RegionId = m.RegionId
left outer join Product on p.ProdId = m.ProdId
left outer join Division on d.DivId = m.DivId
where m.Day = '12-05-2015' and
      m.CompanyId= 15 and
      m.RegionId =10

我希望有一个存储过程可以获得特定部门,产品或公司或两者的汇总统计数据。 SP将根据我们传递的queryParameter返回。 getProductMetrics(queryParam, Day, CompanyId, RegionId, ProdId, DivId) QueryParameter在下面的示例中以括号形式给出。 例如,

  1. (C)获取特定公司的总数量和销售额。即由CompanyId分组
  2. (CR)按公司和地区分组的总数量和销售额。公司与地区之间的不同组合。
  3. (P)按公司分组的总数量和销售
  4. (D)获取特定部门的总数量和销售额。
  5. 依旧...... QueryParameter可能有价值 - C, R, P, CRP, D, CR, CP, CD。对于每个queryParameter,我有select语句。例如下面

    IF @queryParameter IN ('C')
      select m.Day, c.CompanyName, 'ALL' as Region, 'ALL' as ProductName, 'ALL' as DivisionName, SUM(m.Quantity), SUM(m.Sale)
        from ProductMetrics m
        left outer join Company on c.CompanyId = m.CompanyId
        where m.Day = '12-05-2015' and
            c.CompanyId =23
        group by m.Day, c.CompanyName
    

    所以...... 以上存储过程为我提供了特定产品和日期所有可用部门区域的总销售额。

    对于存储过程,我需要写入8个具有IF条件的选择状态。

    问题是,而不是8个不同的select语句,我应该使用CASE语句只有单个storedProc吗?

    我在下面尝试过 -

    Select m.Day as Date,
           CASE @QueryParameter
              WHEN IN (C, CRP, CP, CR, CD) THEN c.CompanyName
              ELSE 'ALL'
            END as 'CompanyName',
    
            CASE @QueryParameter
              WHEN IN (R, CR) THEN r.RegionName
              ELSE 'ALL'
            END as 'RegionName',
    
            CASE @QueryParameter
              WHEN IN (P, CRP, CP) THEN p.ProductName
              ELSE 'ALL'
            END as 'ProductName',
    
            CASE @QueryParameter
              WHEN IN (D, CD) THEN d.DivisionName
              ELSE 'ALL'
            END as 'DivisionName',
    
            SUM(Quantity), SUM(Sale)
    from ProductMetrics m,
    left outer join Company on c.CompanyId = m.CompanyId
    left outer join Region on r.RegionId = m.RegionId
    left outer join Product on p.ProdId = m.ProdId
    left outer join Division on d.DivId = m.DivId
    
    where m.Day='12-5-2015' and
          r.Region = @region and
          p.ProdId = @product
          c.CompanyId = @company and
          d.DivId = @division
    group by Day, CompanyName,RegionName, ProductName, DivisionName
    

    如您所知,还应该为join,where和group by语句提供case语句。因为QueryParameter' CR',divionId和ProdId将作为null传递。 我将使用下面的exec运行storedProc(QueryParameter,CompID,RegionId,ProdId,DivId) EXEC getProductMetrics('CR',23, 39, '','') // CR requires only CompID and RegionId

    EXEC getProductMetrics('CD',23, '', '',100) // CD requires only CompID and DivId
    

    等等.. 你能帮助我获得这个优化的查询吗?

2 个答案:

答案 0 :(得分:2)

为了以简单易读的方式执行此操作,我将创建一些辅助逻辑变量,如 @ByCompany ,以检查是否应按公司分组等等。然后我会解释输入并相应地设置这些变量,然后在 SELECT WHERE GROUP BY 中创建一个使用它们的语句(并且可能 ORDER BY 部分。不过,我认为不需要在 FROM 部分使用它们。

下面是一些示例代码 - 对于TransactSQL中的任何错误感到抱歉 - 我暂时没有使用它。 ;)

DECLARE @ByCompany BIT = 0;
DECLARE @ByRegion BIT = 0;
[..]
IF @QueryParameter LIKE ('%C%') @ByCompany = 1
IF @QueryParameter LIKE ('%R%') @ByRegion = 1
[..]
Select 
    m.Day as Date,
    CASE @ByCompany WHEN 1 THEN c.CompanyName ELSE 'ALL' END as 'CompanyName',
    CASE @ByRegion  WHEN 1 THEN r.RegionName  ELSE 'ALL' END as 'RegionName',
    [..]
    SUM(Quantity), 
    SUM(Sale)
from 
    ProductMetrics m,
left outer join Company on c.CompanyId = m.CompanyId
left outer join Region on r.RegionId = m.RegionId
[..]
where m.Day='12-5-2015'
and (c.CompanyId = @company OR @ByCompany = 0)
and (r.Region = @region OR @ByRegion = 0)
[..]
group by 
    Day, 
    CASE @ByCompany WHEN 1 THEN c.CompanyName ELSE 'ALL' END,
    CASE @ByRegion  WHEN 1 THEN r.RegionName  ELSE 'ALL' END,
    [..]

这样做,我们有简单易读的查询,当我们想要添加另一列进行分组时,我们会保留这些查询,例如subregion。

答案 1 :(得分:0)

SELECT m.Day AS Date,
CASE @QueryParameter
      WHEN EXISTS (C, CRP, CP, CR, CD) THEN (select c.CompanyName from Company where c.CompanyId= @company)
      ELSE 'ALL'
    END as 'CompanyName',

    CASE @QueryParameter
      WHEN exists (R, CR) THEN (select r.RegionName from Region r where r.RegionId=@region)
      ELSE 'ALL'
    END as 'RegionName',

    CASE @QueryParameter
      WHEN exists (P, CRP, CP) THEN (select p.ProductName from Product p where p.ProdId =@product)
      ELSE 'ALL'
    END as 'ProductName',
    CASE @QueryParameter
      WHEN exists (D, CD) THEN (select d.DivisionName from  Division where d.DivId = @division)
      ELSE 'ALL'
    END as 'DivisionName',
    SUM(Quantity), SUM(Sale)
    from ProductMetrics m
    where m.Day='12-5-2015'

删除了联接并添加了子查询,试试这个。