如何避免在查询中复制子查询

时间:2016-03-13 04:28:02

标签: sql-server subquery

我运行的查询包含两次相同的子查询,一个用于内连接条件,另一个用于外连接。我用**强调了重复的子查询。我怎样才能优化它才能只运行一次?

SELECT DISTINCT dbo.tb_contato.Nome, dbo.tb_contato.id_contato, dbo.tb_contato.Sexo, dbo.tb_contato.codigo, dbo.tb_email.email
FROM         dbo.tb_contato INNER JOIN
                      dbo.tb_email ON dbo.tb_contato.id_contato = dbo.tb_email.id_contato INNER JOIN
                      dbo.tb_empresa ON dbo.tb_empresa.id_empresa = dbo.tb_contato.id_empresa LEFT OUTER JOIN
                          (SELECT     dbo.tb_interacao.IDContato AS id_contato
                            FROM          dbo.tb_interacao INNER JOIN
                                                       **(SELECT     MAX(IDInteracao) AS IDIntMax, IDPerfilParticipante AS id_perfil_participante, IDProjeto, IDContato
                                                         FROM          dbo.tb_interacao AS tb_interacao_2
                                                         GROUP BY IDPerfilParticipante, IDProjeto, IDContato)** AS IntMax1 ON dbo.tb_interacao.IDInteracao = IntMax1.IDIntMax INNER JOIN
                                                   dbo.tb_projeto ON dbo.tb_interacao.IDProjeto = dbo.tb_projeto.id_projeto INNER JOIN
                                                   dbo.tb_status_processo ON dbo.tb_interacao.IDStatusProcesso = dbo.tb_status_processo.id_status_processo
                            WHERE      (dbo.tb_projeto.id_projeto = 2057) AND (dbo.tb_interacao.IDPerfilParticipante = 1) AND (dbo.tb_status_processo.id_status_processo = 7) OR
                                                   (dbo.tb_projeto.id_projeto = 2057) AND (dbo.tb_interacao.IDPerfilParticipante = 1) AND (dbo.tb_status_processo.id_status_processo = 6) OR
                                                   (dbo.tb_interacao.IDPerfilParticipante = 1) AND (dbo.tb_status_processo.id_status_processo = 6) AND (dbo.tb_projeto.id_grupo = 55) OR
                                                   (dbo.tb_interacao.IDPerfilParticipante = 1) AND (dbo.tb_status_processo.id_status_processo = 7) AND (dbo.tb_projeto.id_grupo = 55)) 
                      AS ConvidadosOut ON dbo.tb_contato.id_contato = ConvidadosOut.id_contato INNER JOIN
                          (SELECT     tb_interacao_1.IDContato AS id_contato
                            FROM          dbo.tb_interacao AS tb_interacao_1 INNER JOIN
                                                       **(SELECT     MAX(IDInteracao) AS IDIntMax, IDPerfilParticipante AS id_perfil_participante, IDProjeto, IDContato
                                                         FROM          dbo.tb_interacao AS tb_interacao_3
                                                         GROUP BY IDPerfilParticipante, IDProjeto, IDContato)** AS IntMax2 ON tb_interacao_1.IDInteracao = IntMax2.IDIntMax INNER JOIN
                                                   dbo.tb_projeto AS tb_projeto_1 ON tb_interacao_1.IDProjeto = tb_projeto_1.id_projeto INNER JOIN
                                                   dbo.tb_status_processo AS tb_status_processo_1 ON tb_interacao_1.IDStatusProcesso = tb_status_processo_1.id_status_processo
                            WHERE      (tb_projeto_1.id_projeto = 181) AND (IntMax2.id_perfil_participante = 1) AND (tb_status_processo_1.id_status_processo = 4) OR
                                                   (tb_projeto_1.id_projeto = 1581) AND (IntMax2.id_perfil_participante = 1) AND (tb_status_processo_1.id_status_processo = 5) OR
                                                   (IntMax2.id_perfil_participante = 1) AND (tb_status_processo_1.id_status_processo = 6) AND (tb_projeto_1.id_grupo = 62)) AS ConvidadosIn ON 
                      dbo.tb_contato.id_contato = ConvidadosIn.id_contato
WHERE     (dbo.tb_email.email_visibility = 0 OR
                      dbo.tb_email.email_visibility IS NULL) AND (dbo.tb_empresa.id_pais = 1) AND (dbo.tb_contato.Fonte <> 'salesloft_orange' AND 
                      dbo.tb_contato.Fonte <> 'salesloft_int_orange' OR
                      dbo.tb_contato.Fonte IS NULL) AND (dbo.tb_contato.id_contato_visibility = 1 OR
                      dbo.tb_contato.id_contato_visibility IS NULL) AND (ConvidadosOut.id_contato IS NULL)

1 个答案:

答案 0 :(得分:1)

我希望您使用的是SQL Server 2005或更高版本。您可以安全地尝试使用Common表表达式来达到问题中所述的目的。 以下是来自adventureworks数据库的脚本示例:

USE AdventureWorks2008R2;
GO
-- Define the CTE expression name and column list.
WITH Sales_CTE (SalesPersonID, SalesOrderID, SalesYear)
AS
-- Define the CTE query.
(
    SELECT SalesPersonID, SalesOrderID, YEAR(OrderDate) AS SalesYear
    FROM Sales.SalesOrderHeader
    WHERE SalesPersonID IS NOT NULL
)
-- Define the outer query referencing the CTE name.
SELECT SalesPersonID, COUNT(SalesOrderID) AS TotalSales, SalesYear
FROM Sales_CTE
GROUP BY SalesYear, SalesPersonID
ORDER BY SalesPersonID, SalesYear;
GO