我有一个BIG(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个查询)吗?
谢谢!
答案 0 :(得分:0)
您可以使用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;
答案 1 :(得分:0)
我想我明白了
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;
我认为它确实可以解释我的意图。
这对您有意义吗?
谢谢!
答案 2 :(得分:0)
检查是否有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
顺便说一句。我试图分析您的查询,但是它引发了一些奇怪的错误,我放弃了。在这里,您只需触摸表格一次,就不会自我连接,因此应该更快。