Избежание нескольких повторяющихся подзапросов, которые используются для получения столбцов в select - PullRequest
0 голосов
/ 12 июня 2018

У меня есть представление, состоящее из нескольких подзапросов, которые используются для получения столбцов в списке выбора (для простоты я не указал все подзапросы).Мой вопрос здесь заключается в том, что вполне нормально написать такой запрос с таким количеством подзапросов или есть лучший способ переписать его, чтобы избежать их ... любых лучших практик, которые можно использовать.Я попытался найти вариант выполнения производного запроса или 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 голосов
/ 12 июня 2018

В случае:

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 см. это и это например:

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
  )
0 голосов
/ 12 июня 2018

Вы можете переписать ваш выбор, используя 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;

Таким способом можно объединить несколько предложений.

...