Объединить повторяющиеся идентичные подзапросы - PullRequest
0 голосов
/ 28 декабря 2018

Как мне удалить или объединить три идентичных подзапроса в моем запросе ниже?

Подробности использования: я работаю с таблицей Projects , в которой перечислено несколько миллионов проектов.Каждая запись проекта имеет Создателя, Администратора и Редактора, как указано системным идентификатором.Я хочу заменить эти системные идентификаторы соответствующими именами, содержащимися в таблице Сотрудники .Для перекрестной ссылки на системные идентификаторы и имена необходима третья таблица Users и ее поле hr_id.

Projects:
--prj-- --name-- -owner- -creator- -editor- --many more columns...
 001     alpha    001Z     300Z     304Z       ...
 002     beta     020Z     350Z     600Z       ...
 003     charlie  600Z     020Z     001Z       ...


Employees:                       Users:               
--hr_id-- --name--                 -hr_id- -sys_id-
 A01    john                      A01     001Z
 A02    susan                     A02     020Z
 A03    ryan                      A03     300Z
 A04    kelly                     A04     304Z
 A05    matt                      A05     350Z
 A06    bert                      A06     600Z

Desired output:
--prj-- --name-- -owner- -creator- -editor- --adt'l cols...
 001     alpha    john     ryan     kelly    ...
 002     beta     susan    matt     bert     ...
 003     charlie  bert     susan    john     ...

Ниже приведен мой код, включая несколько несвязанных объединений, которые должны остаться.Мой запрос работает, как и ожидалось, но он неэффективен, и я был бы признателен за совет.Кроме того (из моего поиска в Google я считаю, что это актуально), я работаю в среде, не дружественной CTE.

SELECT projects.prj As project_id,
       projects.name As project_name,
       owner.name As owner_name,
       creator.name As creator_name,
       editor.name As editor_name,
       stats.stat1 As stat_1,
       actuals.stat2 As stat_2
FROM "dbconnect"."projects" As projects
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS owner ON projects.owner = owner.sys_id
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS creator ON projects.creator = creator.sys_id
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS editor ON projects.editor = editor.sys_id
  LEFT JOIN "dbconnect"."prjstats" As stats ON projects.prj = prjstats.prj_id
  LEFT JOIN "dbconnect"."prjactuals" As actuals ON projects.prj = prjactuals.prj_id

Ответы [ 2 ]

0 голосов
/ 28 декабря 2018

Просто используйте CTE.Я предпочитаю left join s, поэтому я бы написал это как:

WITH eu as (
      SELECT e.name, u.hr_id, u.sys_id
      FROM "dbconnect"."users" u LEFT JOIN
           "dbconnect"."employees" e
           ON e.hr_id = u.hr_id
     )       
SELECT p.prj As project_id, p.name As project_name,
       euo.name As owner_name, euc.name As creator_name,
       eue.name As editor_name,
       ps.stat1 As stat_1,
       pa.stat2 As stat_2
FROM "dbconnect"."projects" p LEFT JOIN
     eu euo 
     ON p.owner = euo.sys_id LEFT JOIN
     eu euc
     ON p.creator = euc.sys_id LEFT JOIN
     eu eue
     ON p.editor = eue.sys_id LEFT JOIN
     "dbconnect"."prjstats" ps
     ON p.prj = ps.prj_id LEFT JOIN
     "dbconnect"."prjactuals" pa
     ON p.prj = pa.prj_id;
0 голосов
/ 28 декабря 2018

Вы можете создать скалярную функцию для подзапроса, а затем переписать запрос следующим образом.

CREATE FUNCTION dbo.getName (@id varchar(30))  
RETURNS varchar(128) 
AS  
BEGIN  
     DECLARE @v_name varchar(128) 
     SELECT @v_name=emps.name 
     FROM "dbconnect"."employees" AS emps
     RIGHT JOIN "dbconnect"."users" AS users ON emps.hr_id = users.hr_id
     WHERE users.sys_id=@id

     RETURN @v_name
END

--Query
SELECT projects.prj As project_id,
       projects.name As project_name,
       /*
       owner.name As owner_name,
       creator.name As creator_name,
       editor.name As editor_name,
       */
       dbo.getName(projects.owner) as owner_name,
       dbo.getName(projects.creator) as creator_name,
       dbo.getName(projects.editor) as editor_name,
       stats.stat1 As stat_1,
       actuals.stat2 As stat_2
FROM "dbconnect"."projects" As projects
/*
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS owner ON projects.owner = owner.sys_id
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS creator ON projects.creator = creator.sys_id
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS editor ON projects.editor = editor.sys_id
*/
  LEFT JOIN "dbconnect"."prjstats" As stats ON projects.prj = prjstats.prj_id
  LEFT JOIN "dbconnect"."prjactuals" As actuals ON projects.prj = prjactuals.prj_id

Или вы можете создать табличную функцию, а затем использовать оператор APPLY для присоединения к функции.

CREATE FUNCTION dbo.getName (@id varchar(30))  
RETURNS TABLE
AS  
RETURN
( 
     SELECT emps.name
     FROM "dbconnect"."employees" AS emps
     RIGHT JOIN "dbconnect"."users" AS users ON emps.hr_id = users.hr_id
     WHERE users.sys_id=@id
)

--Query
SELECT projects.prj As project_id,
       projects.name As project_name,
       owner.name As owner_name,
       creator.name As creator_name,
       editor.name As editor_name,
       stats.stat1 As stat_1,
       actuals.stat2 As stat_2
FROM "dbconnect"."projects" As projects
OUTER APPLY dbo.getName(projects.owner) as owner
OUTER APPLY dbo.getName(projects.creator) as creator
OUTER APPLY dbo.getName(projects.editor) as editor
/*
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS owner ON projects.owner = owner.sys_id
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS creator ON projects.creator = creator.sys_id
  LEFT JOIN (
             SELECT emps.name,
                    users.hr_id,
                    users.sys_id
             FROM "dbconnect"."employees" AS emps
             RIGHT JOIN "dbconnect"."users" AS users
               ON emps.hr_id = users.hr_id
            ) AS editor ON projects.editor = editor.sys_id
*/
  LEFT JOIN "dbconnect"."prjstats" As stats ON projects.prj = prjstats.prj_id
  LEFT JOIN "dbconnect"."prjactuals" As actuals ON projects.prj = prjactuals.prj_id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...