2013-05-08 56 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];