避免使用多个重复的子查询来获取select中的列

时间:2018-06-11 22:23:40

标签: sql-server tsql sql-server-2005 sql-tuning

我有一个视图,它包含多个子查询,用于派生选择列表中的列(为了保持简单,我没有指定所有子查询)。我的问题是,用这么多子查询编写这样一个查询是完全可以的,还是有更好的方法来重写它以避免它们......任何可以遵循的最佳实践。我试着看一下派生查询或cte的选项,但由于某种原因我无法将这一块放在一起。我想尽可能消除那些重复的子查询。

  SELECT a.id,
   (
     SELECT TOP 1
      name
     FROM x.dbo.Info l
     WHERE orderno = a.orderno
       AND releaseno = a.releaseno
       AND stamp =
       (
       SELECT MIN(stamp)
       FROM x.dbo.Info
       WHERE orderno = l.orderno
         AND releaseno = l.releaseno
         AND status = 'Released'
       )
     ORDER BY stamp DESC
   ) [shop_name],
   c.line_no,
   a.status,
   d.family,
   (
     SELECT TOP 1
      name
     FROM x.dbo.Info
     WHERE orderno = a.orderno
       AND releaseno = a.releaseno
       AND status NOT LIKE 'backflus%'
       AND status NOT LIKE 'so%'
     ORDER BY stamp DESC
   ) AS [lastworkplace],
   (
     SELECT TOP 1
      lstatus
     FROM x.dbo.Info
     WHERE orderno = a.orderno
       AND releaseno = a.releaseno
       AND status NOT LIKE 'backflus%'
       AND status NOT LIKE 'so%'
     ORDER BY stamp DESC
   ) AS [laststatus]
FROM BI.dbo.tblz a -- this is a view (not sure if that matters)
  LEFT JOIN X.dbo.tblx b
    ON b.id = a.salesorder
  LEFT JOIN X.dbo.tbls c
    ON c.tranid = a.salesorder
     AND c.itemid = a.assemblyid
     AND c.serialnum = a.ordercode
  LEFT JOIN Z.dbo.tbli d
    ON d.prodline = LEFT(COALESCE(STUFF(a.assemblyid, CHARINDEX('+', a.assemblyid), 1, ''), a.assemblyid), 2)
WHERE a.id = 'p'
  AND
  (
    LEFT(a.prun, 8) >= '20120101'
    OR a.prun IS NULL
  )
UNION ALL
SELECT a.id,
   (
     SELECT TOP 1
      name
     FROM x.dbo.Info l
     WHERE orderno = a.orderno
       AND releaseno = a.releaseno
       AND stamp =
       (
       SELECT MIN(stamp)
       FROM x.dbo.Info
       WHERE orderno = l.orderno
         AND releaseno = l.releaseno
         AND status = 'Released'
       )
     ORDER BY stamp DESC
   ) [shop_name],
   c.line_no,
   a.status,
   d.family,
   (
     SELECT TOP 1
      name
     FROM x.dbo.Info
     WHERE orderno = a.orderno
       AND releaseno = a.releaseno
       AND status NOT LIKE 'backflus%'
       AND status NOT LIKE 'so%'
     ORDER BY stamp DESC
   ) AS [lastworkplace],
   (
     SELECT TOP 1
      lstatus
     FROM x.dbo.Info
     WHERE orderno = a.orderno
       AND releaseno = a.releaseno
       AND status NOT LIKE 'backflus%'
       AND status NOT LIKE 'so%'
     ORDER BY stamp DESC
   ) AS [laststatus]
FROM BI.dbo.tblz a -- this is a view (not sure if that matters)
  LEFT JOIN X.dbo.tblx b
    ON b.id = a.salesorder
  LEFT JOIN X.dbo.tbls c
    ON c.tranid = a.salesorder
     AND c.itemid = a.assemblyid
     AND c.serialnum = a.ordercode
  LEFT JOIN Z.dbo.tbli d
    ON d.prodline = LEFT(COALESCE(STUFF(a.assemblyid, CHARINDEX('+', a.assemblyid), 1, ''), a.assemblyid), 2)
WHERE a.id = 'm'
  AND
  (
    LEFT(a.prun, 8) >= '20120101'
    OR a.prun IS NULL
  );

2 个答案:

答案 0 :(得分:0)

您可以使用CTE重写您的选择。它更具可读性。引用文档:

  

指定临时命名结果集,称为公用表表达式(CTE)。这是从简单查询派生而来,并在单个SELECT,INSERT,UPDATE或DELETE语句的执行范围内定义。此子句也可以在CREATE VIEW语句中用作其定义SELECT语句的一部分。公用表表达式可以包含对自身的引用。这被称为递归公用表表达式。

只是一个简单的示例:

WITH 
 step1 as 
  ( select a+1 as x, b-1 as y
    from t
  ),
 step2 as
  ( select x*2 as i, y/2 as j
    from step1
  )
select i+j as r
from step2;

你可以用这种方式链接几个句子。

答案 1 :(得分:0)

以下情况:

SELECT TOP 1
    [some column]
FROM x.dbo.Info
WHERE orderno = a.orderno
    AND releaseno = a.releaseno
    AND status NOT LIKE 'backflus%'
    AND status NOT LIKE 'so%'
ORDER BY stamp DESC

您可以尝试OUTER APPLY查看thisthis例如:

SELECT a.id,
   (
     SELECT TOP 1
      name
     FROM x.dbo.Info l
     WHERE orderno = a.orderno
       AND releaseno = a.releaseno
       AND stamp =
       (
       SELECT MIN(stamp)
       FROM x.dbo.Info
       WHERE orderno = l.orderno
         AND releaseno = l.releaseno
         AND status = 'Released'
       )
     ORDER BY stamp DESC
   ) [shop_name],
   c.line_no,
   a.status,
   d.family,
   SomeInfo.name AS [lastworkplace], --<-- Note the change
   SomeInfo.lstatus AS [laststatus] --<-- Note the change
FROM BI.dbo.tblz a -- this is a view (not sure if that matters)
  LEFT JOIN X.dbo.tblx b
    ON b.id = a.salesorder
  LEFT JOIN X.dbo.tbls c
    ON c.tranid = a.salesorder
     AND c.itemid = a.assemblyid
     AND c.serialnum = a.ordercode
  LEFT JOIN Z.dbo.tbli d
    ON d.prodline = LEFT(COALESCE(STUFF(a.assemblyid, CHARINDEX('+', a.assemblyid), 1, ''), a.assemblyid), 2)

    OUTER APPLY(  --<-- Note the extra join
        SELECT TOP 1
            *
        FROM x.dbo.Info
        WHERE orderno = a.orderno
            AND releaseno = a.releaseno
            AND status NOT LIKE 'backflus%'
            AND status NOT LIKE 'so%'
        ORDER BY stamp DESC
    ) AS SomeInfo
WHERE a.id = 'p'
  AND
  (
    LEFT(a.prun, 8) >= '20120101'
    OR a.prun IS NULL
  )