[英]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
順便提一句。 我試圖分析你的查詢,但它拋出了一些奇怪的錯誤,我放棄了。 在這里你只接觸 table 一次,沒有 self-joins,所以它應該更快。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.