我正在尝试解决一个出色的问题。我想在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。
例如,


(C)获取特定公司的总数量和销售量。即按CompanyId分组
(CR)按公司和地区分组的总数量和销售量。公司和地区之间的不同组合。
(P)按公司分组的总数量和销售量
(D)获取特定部门的总数量和销售量。


等等...
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


如您所知,case语句也应存在于join,where和group by语句中。因为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


等等..
您能协助我获得此优化查询吗?

最佳答案

为此,我将创建一些辅助逻辑变量(如@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。

关于sql - select,where和group by子句中的多个CASE表达式,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39137120/

10-09 10:02