Sql server 如何避免在查询中重复子查询

Sql server 如何避免在查询中重复子查询,sql-server,subquery,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

我运行了两次包含相同子查询的查询,一次用于内部联接条件,另一次用于外部联接。我用**突出显示重复的子查询。我如何优化它,以便只运行一次

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)

我希望您使用的是SQL server 2005或更高版本。您可以安全地尝试使用公共表表达式来达到问题中所述的目的。 以下是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 

听起来是个好主意,但我不确定如何在两个选择中使用CTE。我还没有发现任何我两次调用CTE的例子。有什么建议吗?谢谢。如果只是在同一个查询中调用CTE,您可以随时调用CTE。您可以通过Pinal Dave在Thank You Kasim检查同一查询中的多个CTE使用情况。它起作用了,但处理时间是一样的。一旦我只运行一次CTE,它不应该变得更快吗?CTE只对脚本编写的简单性有用。在执行期间,CTE将在最终查询中被替换,因此原始脚本和带有CTE的脚本的执行计划将完全相同。如果您希望获得性能,可以考虑使用表变量。