簡體   English   中英

有沒有辦法在一個簡單的查詢中做到這一點?

[英]Is there a way to do this in a simple query?

我有一個大(2300 萬行)表 CONTRATOS,其中包含以下列:

SELECT
    CONTRATO,
    CODIGO_ORIGEN,
    ORIGEN
FROM CONTRATOS;

CODIGO_ORIGEN 列有多個具有相同值的行:

CODIGO_ORIGEN     CONTRATO       ORIGEN 
-------------    ----------     --------
     1               345          CONT
     1               363          BKP
     1               645          BKP
     1               365          CONT 

我只需要為每個 CODIGO_ORIGEN 獲取一個 CONTRATO,但始終優先考慮“CONT”值。 所以在這個示例中,它將是值為365的 CONTRATO

我試圖做這樣的事情:

SELECT  
   CODIGO_ORIGEN,
   CASE
    WHEN ORIGEN = 'CONT' THEN
        FIRST_VALUE (CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CONTRATO DESC) 
    WHEN ORIGEN = 'BKP' THEN
        FIRST_VALUE (CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CAMPO1 DESC, CAMPO2 DESC, CONTRATO DESC) 
   END AS CONTRATO
FROM CONTRATOS;

如果 ORIGEN 是 'CONTR',我應該按最高的 CONTRATO 排序並獲得 CONTRATO 列。 如果 ORIGEN 是“BKP”,我應該按不同的列排序並獲取 CONTRATO 列。

最后,我應該能夠使用 CODIGO_ORIGEN -> CONTRATO (1:1) 獲得一個唯一的行。

有沒有一種簡單的方法可以做到這一點(1 個查詢)?

提前致謝!

您可以使用ROW_NUMBER來對每個codigo_origen的行進行排名。 這是編寫其ORDER BY子句的一種方法。 還有其他人。

select *
from
(
  select  
     c.*,
     row_number() over (
       partition by codigo_origen 
       order by 
         case when origen 'BKP' then campo1 end desc,
         case when origen 'BKP' then campo2 end desc,
         origen desc
     ) as rn
  from contratos c
) ranked
where rn = 1
order by codigo_origen;

我想我明白了:

      SELECT 
        C.contrato, C.codigo_origen,  NVL2(MX.CONTRATO, NULL, 'F') AS ESTADO, NVL2(MX.CONTRATO, NULL, '4008') AS ERROR
      FROM MGR_CUENTA_CTL C
      LEFT JOIN
      (
          select /*+ PARALLEL */
            DISTINCT CODIGO_ORIGEN,
            CASE
              WHEN ORIGEN_TABLA = 'CONT' THEN FIRST_VALUE(CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CONTRATO DESC) 
              WHEN ORIGEN_TABLA = 'BKP' THEN FIRST_VALUE(CONTRATO) OVER (PARTITION BY CODIGO_ORIGEN ORDER BY CAMPO1 DESC, CAMPO2 DESC) 
            END AS CONTRATO
          FROM
          (  
             SELECT /*+ PARALLEL */ ctl.*
             FROM mgr_cuenta_ctl ctl
             LEFT JOIN 
             (
                   select /*+ PARALLEL */ CODIGO_ORIGEN
                   from mgr_cuenta_ctl
                   group by codigo_origen having count(distinct origen) > 1
             ) CTL2 ON ctl.CODIGO_ORIGEN = ctl2.CODIGO_ORIGEN
             WHERE (CTL2.CODIGO_ORIGEN IS NOT NULL AND CTL.ORIGEN <> 'BKP') OR (CTL2.CODIGO_ORIGEN IS NULL)
          )
      ) MX ON MX.CONTRATO = C.CONTRATO;

我認為它做了我試圖解釋的事情。

它對你有意義嗎?

謝謝!

檢查是否有origen = 'CONT' ,使用解析count() 如果是 - 使用具有第一排序方法的分析函數,如果沒有 - 第二排序:

select mgr_cuenta_ctl.*,
       case 
       when count(case origen when 'CONT' then 1 end) over (partition by codigo_origen) > 0
       then first_value(contrato) over (
            partition by codigo_origen
            order by case origen when 'CONT' then 1 end, contrato desc)
       else first_value(contrato) over (
            partition by codigo_origen
            order by case origen when 'BKP' then 1 end, campo1 desc, campo2 desc, contrato desc)
       end as best
  from mgr_cuenta_ctl

如果您只需要分組值而沒有詳細信息,請刪除partition by子句:

select codigo_origen,
       case when count(case origen when 'CONT' then 1 end) > 0
       then max(contrato) keep (dense_rank first 
                order by case origen when 'CONT' then 1 end, contrato desc) 
       else max(contrato) keep (dense_rank first 
                order by case origen when 'BKP' then 1 end, campo1 desc, campo2 desc) 
       end as best
  from mgr_cuenta_ctl
  group by codigo_origen

dbfiddle 演示

順便提一句。 我試圖分析你的查詢,但它拋出了一些奇怪的錯誤,我放棄了。 在這里你只接觸 table 一次,沒有 self-joins,所以它應該更快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM