【问题标题】:How to join one select with another when the first one not always returns a value for specific row?当第一个选择并不总是返回特定行的值时,如何将一个选择与另一个选择相结合?
【发布时间】:2015-06-23 23:08:30
【问题描述】:

我有一个复杂的查询来检索一些结果:

EDITED QUERY(添加了 UNION ALL):

SELECT  t.*
FROM (

    SELECT  
        dbo.Intervencao.INT_Processo, analista, 
        ETS.ETS_Sigla, ATC.ATC_Sigla, PAT.PAT_Sigla, dbo.Assunto.SNT_Peso,
        CASE 
            WHEN ETS.ETS_Sigla = 'PE' AND (PAT.PAT_Sigla = 'LIB' OR PAT.PAT_Sigla = 'LBR') THEN (0.3*SNT_Peso) 
            WHEN ETS.ETS_Sigla = 'CD' THEN (0.3*SNT_Peso)*0.3  
            ELSE SNT_Peso
        END AS PESOAREA,
        CASE 
            WHEN a.max_TEA_FimTarefa IS NULL THEN a.max_TEA_InicioTarefa
            ELSE a.max_TEA_FimTarefa
        END AS DATA_INICIO_TERMINO,
        ROW_NUMBER() OVER (PARTITION BY ATC.ATC_Sigla, a.SRV_Id ORDER BY TEA_FimTarefa DESC) AS seqnum 
    FROM dbo.Tarefa AS t

    INNER JOIN (
        SELECT 
            MAX(dbo.TarefaEtapaAreaTecnica.TEA_InicioTarefa) AS max_TEA_InicioTarefa,
            MAX (dbo.TarefaEtapaAreaTecnica.TEA_FimTarefa) AS max_TEA_FimTarefa,
            dbo.Pessoa.PFJ_Descri AS analista, dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id
        FROM dbo.TarefaEtapaAreaTecnica 
        LEFT JOIN dbo.Tarefa ON dbo.TarefaEtapaAreaTecnica.TRF_Id = dbo.Tarefa.TRF_Id
        LEFT JOIN dbo.AreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.AreaTecnica.ATC_Id 
        LEFT JOIN dbo.ServicoAreaTecnica ON dbo.TarefaEtapaAreaTecnica.ATC_Id = dbo.ServicoAreaTecnica.ATC_Id 
            AND dbo.Tarefa.SRV_Id = dbo.ServicoAreaTecnica.SRV_Id
        INNER JOIN dbo.Pessoa ON dbo.Pessoa.PFJ_Id = dbo.ServicoAreaTecnica.PFJ_Id_Analista
        GROUP BY dbo.AreaTecnica.ATC_Id, dbo.Tarefa.SRV_Id, dbo.Pessoa.PFJ_Descri
    ) AS a ON t.SRV_Id = a.SRV_Id

    INNER JOIN dbo.TarefaEtapaAreaTecnica AS TarefaEtapaAreaTecnica_1 ON 
        t.TRF_Id = TarefaEtapaAreaTecnica_1.TRF_Id 
        AND a.ATC_Id = TarefaEtapaAreaTecnica_1.ATC_Id 
        AND a.max_TEA_InicioTarefa = TarefaEtapaAreaTecnica_1.TEA_InicioTarefa
    LEFT JOIN AreaTecnica ATC ON TarefaEtapaAreaTecnica_1.ATC_Id = ATC.ATC_Id
    LEFT JOIN Etapa ETS ON TarefaEtapaAreaTecnica_1.ETS_Id = ETS.ETS_Id
    LEFT JOIN ParecerTipo PAT ON TarefaEtapaAreaTecnica_1.PAT_Id = PAT.PAT_Id
    LEFT OUTER JOIN dbo.Servico ON a.SRV_Id = dbo.Servico.SRV_Id
    INNER JOIN dbo.Intervencao ON dbo.Servico.INT_Id = dbo.Intervencao.INT_Id
    LEFT JOIN dbo.Assunto ON dbo.Servico.SNT_Id = dbo.Assunto.SNT_Id

) t

结果如下:

效果很好,问题是我被问到如果该查询中不存在行时,它必须包含来自另一个表 (ServicoAreaTecnica) 的值,所以我根据关键信息得到另一个表的查询的第一个查询。所以如果我联合所有我得到这个:

Query1 + 

UNION ALL

     SELECT INN.INT_Processo, 
            PES.PFJ_Descri,
            NULL, --ETS.ETS_Sigla, 
            ART.ATC_Sigla, 
            NULL ,--PAT.PAT_Sigla,
            ASS.SNT_Peso,
            NULL, --PESOAREA
            NULL, --DATA_INICIO_TERMINO
            NULL --seqnum

     FROM dbo.ServicoAreaTecnica AS SAT
     INNER JOIN dbo.AreaTecnica AS ART ON ART.ATC_Id = SAT.ATC_Id
     INNER JOIN dbo.Servico AS SER ON SER.SRV_Id = SAT.SRV_Id
     INNER JOIN dbo.Assunto AS ASS ON ASS.SNT_Id = SER.SNT_Id
     INNER JOIN dbo.Intervencao AS INN ON INN.INT_Id = SER.INT_Id
     INNER JOIN dbo.Pessoa AS PES ON PES.PFJ_Id = SAT.PFJ_Id_Analista

结果如下:

所以我想做的是删除第 1 行,因为第 2 行存在于第一个查询中,我想这次我得到了更好的解释。结果应该只有第 1 行,只有当查询 1 没有检索到该特定 INN.INT_Processo 的行时才会出现第 2 行。

谢谢!

【问题讨论】:

  • 所以你想加入两个查询并且只显示三列。但是一个查询会过滤掉另一个查询所需的信息?我对问题所在感到困惑。
  • 你能添加一个你预期结果的例子吗?
  • 我觉得sql语句太多会混淆,你能不能把关键问题抽象出来——你想要什么?一些示例或图片会有所帮助。
  • @jpyams 我已经编辑了我的帖子,我认为现在更清楚了。谢谢!
  • @APH 我添加了 2 张新图片,感谢回复

标签: sql-server join union


【解决方案1】:

好的,有两种方法可以减少您的记录集。鉴于您已经编写了代码来生成带有额外行的表,因此最简单的方法可能是添加代码来减少它:

Select * from 
    (Select *
      , Row_Number() over 
           (partition by IntProcesso, Analista order by ISNULL(seqnum, 0) desc) as RN
    from MyResults) a
where RN = 1

这会将row_number 1 分配给来自您的第一个查询的任何行,或来自第二个查询但在第一个查询中没有匹配的任何行,然后过滤掉多余的行。

您也可以按照其他人的建议将外连接与isnullcoalesce 一起使用。像这样的:

Select ISNULL(a.IntProcesso, b.IntProcesso) as IntProcesso
    , ISNULL(a.Analista, b.Analista) as Analista
    , ISNULL(a.ETSsigla, b.ETSsigla) as ETSsigla
    [repeat for the rest of your columns]
from Table1 a
full outer join Table2 b
on a.IntProcesso = b.IntProcesso and a.Analista = b.Analista

【讨论】:

    【解决方案2】:

    您的代码很难阅读,因为所有内容的名称都很冗长(老实说,它们使用的语言是我不会说的语言,这也让阅读变得更加困难)。

    但是如何:用LEFT JOINs 替换您的INNER JOINs,添加更多LEFT JOINs 以在替代表中绘制,并为您希望在结果中的每个变量引入ISNULL 子句?

    【讨论】:

    • @crawletas:是的,UNION 不是这里的路。如果您不知道如何使用LEFT JOIN,那么您可以将所有结果插入到一个临时表中,然后将第二个查询作为第二个单独的插入来处理吗?然后,您可以将插入限制为那些还没有条目的行。最后,使用您想要的任何ORDER BY 规则从临时表中选择。
    【解决方案3】:

    如果您执行... Query1 Right Join Query2 On ... 之类的操作,则应该只获取 Query2 中未出现在 Query 1 中的行。

    【讨论】:

      猜你喜欢
      • 2019-03-21
      • 1970-01-01
      • 2015-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-30
      • 1970-01-01
      相关资源
      最近更新 更多