2016-03-13 90 views
1

我正在運行一個包含兩次相同子查詢的查詢,一個用於內部聯接條件,另一個用於外部聯接。我正在用**強調重複的子查詢。我怎樣才能優化這個只能運行一次?如何避免在查詢中複製子查詢

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

我希望你使用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 
+0

聽起來是個好主意,但我不知道如何在兩個選擇使用CTE。我沒有找到任何兩次致電CTE的例子。有什麼建議麼?謝謝。 – Richard

+0

如果在同一查詢中調用CTE,則可以多次調用CTE。您可以在http://blog.sqlauthority.com/2009/08/08/sql-server-multiple-cte-in-one-select-statement-query/ –

+0

上檢查Pinal Dave在同一查詢中的多個CTE使用情況。謝謝你卡西姆。它的工作,但處理時間是相同的。一旦我只運行一次CTE,它不應該變得更快嗎? – Richard