2016-08-25 139 views
4

我正試圖解決其中一個明智的問題。我想在sql中使用大小寫來優化SQL存儲過程。多個CASE表達式在select中,where和group by子句

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)獲取特定公司的總數量和銷售額。即集團公司ID
  2. (CR)總量和銷售按公司和地區分組。公司和地區之間的不同組合。
  3. (P)總數量和銷售量按公司分組
  4. (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 

於是就.. 上面的存儲過程讓我從所有可用的分工,區域特定的產品和日銷售總額。

對於存儲過程,我需要用IF條件編寫8個select語句。

問題是不是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語句也應該存在的捧場,其中和GROUP BY語句。因爲QueryParameter'CR',divionId和ProdId將作爲null傳遞。 我將與運行storedProc(QueryParameter,CompID,RegionId,PRODID,DIVID)以下EXEC EXEC getProductMetrics('CR',23, 39, '','') // CR requires only CompID and RegionId

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

等.. 你能幫助我獲得這個優化的查詢?

+1

MySQL或SQL Server? (打定主意) – Barranka

+0

SQL Server;)我將不勝感激您的建議 –

+1

爲什麼你堅持要有一條select語句?我會使用IF ... ELSE來評估哪些參數是NULL,然後爲它們生成單獨的select語句。查詢優化器可能會更好地處理它們,並且代碼更具可讀性。 – PacoDePaco

回答

1

要做到這一點在簡單和可讀的方式,我會創建一些幫助器邏輯變量,如@ByCompany,檢查我們是否應該按公司分組等。然後,我會解釋輸入,並相應地設置這些變量,然後創建一個在使用它們一個語句selectWHEREGROUP BY(可能ORDER BY以及)部分。雖然我沒有看到需要在部分使用它們。

下面是一些示例代碼 - 對於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, 
    [..] 

做這樣的說法,我們有簡單易讀的查詢,這將是maintable當我們想添加一個列進行分組,分區域說。

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 [email protected]) 
     ELSE 'ALL' 
    END as 'RegionName', 

    CASE @QueryParameter 
     WHEN exists (P, CRP, CP) THEN (select p.ProductName from Product p where p.ProdId [email protected]) 
     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' 

刪除了連接並添加了子查詢,試試這個。

相關問題