2013-05-08 79 views
3

我有一個簡單的表「TABLE_1」如何優化SQL查詢來實現最小執行時間

Org Customer Code Ordered Deleted Confirmed 

RU  Cust_1  A  1000  800  200 
RU  Cust_2  B  300  0   300 
US  Cust_3  C  800  100  700 
RU  Cust_4  B  100  100  0 
US  Cust_5  C  400  200  200 
RU  Cust_6  B  500  300  200 

現在我需要改變這個表中的行,其中「已刪除」 <> 0喜歡

Org Code Customers   Ordered Confirmed 

RU  A  Cust_1    1000  200 
RU  B  Cust_4, Cust_6  600  200 
US  C  Cust_3, Cust_5  1200  900 

我使用下面的查詢和功能

SELECT T1.Org, 
     T1.Code, 
     dbo.FUNC(T1.Code, T1.Org) AS 'Customers', 
     'Ordered' = (SELECT SUM(Ordered) FROM TABLE_1 AS T2 WHERE T2.Customer = T1.Customer AND T2.Code = T1.Code AND T2.Deleted<>0), 
     'Confirmed' = (SELECT SUM(Confirmed) FROM TABLE_1 AS T3 WHERE T3.Customer = T1.Customer AND T3.Code = T1.Code AND T3.Deleted<>0) 
FROM TABLE_1 AS T1 
WHERE T1.Deleted <> 0 

功能 'FUNC':

ALTER FUNCTION [dbo].[FUNC] (@c VARCHAR(MAX), @org VARCHAR(MAX)) 
RETURNS VARCHAR(MAX) AS BEGIN 
DECLARE @p VARCHAR(MAX) ; 
SET @p = '' ; 
SELECT @p = @p + T1.Customer + ', ' 
FROM TABLE_1 AS T1 
WHERE T1.Code = @c AND T1.Org = @org AND T1.Deleted <> 0 
GROUP BY T1.Customer 
RETURN SUBSTRING(@p, 1, LEN(@p) - 1) 
END 

我認爲這不是如何得到結果的最佳方式,特別是如果我有一張大桌子。 有更好的解決方案嗎?

編輯: 表DDL例如

CREATE TABLE [dbo].[TABLE_1](
[Org] [nchar](10) NULL, 
[Customer] [nchar](100) NULL, 
[Code] [nchar](10) NULL, 
[Ordered] [decimal](18,1) NULL, 
[Deleted] [decimal](18,1) NULL, 
[Confirmed] [decimal](18,1) NULL) 
ON [PRIMARY] 
+0

你真的想在連接字符串中TSQL,有沒有表現層? – Jodrell 2013-05-08 08:21:26

+0

我不知道我明白你的意思。我應該在查詢中使用串聯而不是函數嗎? – mbigun 2013-05-08 08:45:53

+0

對於相同的客戶,組織和代碼是否有可能擁有多行?如果是這樣,大多數提供的答案(到目前爲止)將不會正確工作,而不需要針對不同的客戶進行修復。 – 2013-05-08 09:01:42

回答

2

你將面臨RBAR 「問題」 wathever你選擇這樣做。 但是,您可能會發現使用FOR XML PATH('')+ OUTER APPLY而不是您的函數更好。

如果你不知道這些,我會寫一段代碼來演示用法。 但是,你可以提供你的表DDL第一(+一些行)。

這就是:

SELECT 
    T1.Org 
    , T1.Code 
    , ISNULL(STUFF(F.Customers, 1, 2, ''), '') AS Customers 
    , SUM(T1.Ordered) OVER (PARTITION BY T1.Customer, T1.Code) AS Ordered 
    , SUM(T1.Confirmed) OVER (PARTITION BY T1.Customer, T1.Code) AS Confirmed 
FROM TABLE_1 AS T1 
OUTER APPLY (
    SELECT 
     ', ' + T2.Customer 
    FROM TABLE_1 AS T2 
    WHERE T2.Code = T1.Code 
    AND T2.Org = T1.Org 
    AND T2.Deleted <> 0 
    FOR XML PATH('') 
) AS F(Customers) 
WHERE T1.Deleted <> 0 
+0

謝謝!如果您提供一些CTE解決方案的例子,我將不勝感激。 – mbigun 2013-05-08 08:44:40

+0

對不起,但CTE只會讓查詢實際上運行悲慘,因爲它將依賴ROW_NUMBER,其中PARTITION BY子句不會幫助MSSQL避免執行完整掃描。對不起,我甚至在我的版本之前談過CTE。 – Serge 2013-05-08 08:53:42

+0

@mrbigun似乎不適用於我,http://sqlfiddle.com/#!6/49660/2 – Jodrell 2013-05-08 10:24:13

1

SQLFiddle demo

SELECT 
    Org, 
    Code, 
    STUFF(
     (SELECT ','+Customer 
     FROM t WHERE Code=a.Code and Deleted<>0 
     FOR XML PATH('')) , 1 , 1 , ''), 
    SUM(ordered), 
    SUM(Confirmed) 

FROM 
    t A 
where Deleted<>0 
group by ORG,code 
+0

mbigun在他的查詢中沒有對行進行分組,您的假設對他來說可能是正確的。 – Serge 2013-05-08 09:06:08

1

什麼是最好的可能需要您的具體數據的一些測試,但是對於開始,讓我們解決您的原始查詢,以獲得正確的結果,你在您的問題如預期寫道:

SELECT T1.Org, 
     T1.Code, 
     dbo.FUNC(T1.Code, T1.Org) AS Customers, 
     SUM(Ordered) AS Ordered, 
     SUM(Confirmed) AS Confirmed 
FROM TABLE_1 AS T1 
WHERE T1.Deleted <> 0 
GROUP BY T1.Org, T1.Code 
1

你可以做到這一點,即使您的客戶名稱包含XML控制字符,也應該可以工作。

Fiddle Here

SELECT 
      t1.[Org], 
      t1.[Code], 
      STUFF(
       (
       SELECT 
           ', ' + c.[Customer] 
        FROM 
           [TABLE_1] c 
        WHERE 
           c.[Deleted] <> 0 
         AND 
           c.[Org] = t1.[Org] 
         AND 
           c.[Code] = t1.[Code] 
        ORDER BY 
           c.[Customer] 
        FOR XML PATH (''), TYPE 
       ).value('.', 'varchar(max)'), 
       1, 
       2, 
       '') [Customers], 
      SUM(t1.[Ordered]), 
      SUM(t1.[Confirmed]) 
    FROM 
      [TABLE_1] t1 

    WHERE 
      t1.[Deleted] <> 0 
    GROUP BY 
      t1.[Org], 
      t1.[Code]; 

在性能方面,它是有道理的,只是做兩個查詢和擔心演示文稿作爲一個逗號分隔的列表後。您可以獲得相同的信息,但不會產生MSSQL如此錯誤放置以實現的字符串聚合開銷。

Fiddle Here

SELECT 
      t1.[Org], 
      t1.[Code], 
      SUM(t1.[Ordered]), 
      SUM(t1.[Confirmed]) 
    FROM 
      [TABLE_1] t1 

    WHERE 
      t1.[Deleted] <> 0 
    GROUP BY 
      t1.[Org], 
      t1.[Code]; 

SELECT 
      t1.[Org], 
      t1.[Code], 
      t1.[Customer] 
    FROM 
      [TABLE_1] t1 

    WHERE 
      t1.[Deleted] <> 0 
    ORDER BY 
      t1.[Org], 
      t1.[Code], 
      t1.[Customer];