Sql 在一个简单的查询中有没有办法做到这一点?
我有一个2300万行的大型表CONTRATOS,其中包含以下列:Sql 在一个简单的查询中有没有办法做到这一点?,sql,oracle,group-by,subquery,Sql,Oracle,Group By,Subquery,我有一个2300万行的大型表CONTRATOS,其中包含以下列: SELECT CONTRATO, CODIGO_ORIGEN, ORIGEN FROM CONTRATOS; CODIGO_ORIGEN列有多行具有相同的值: CODIGO_ORIGEN CONTRATO ORIGEN ------------- ---------- -------- 1 345 CONT
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的对立面
我试着做这样的事情:
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\u NUMBER按codigo\u origen对行进行排序。下面是一种编写ORDERBY子句的方法。还有其他的
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',使用分析计数。如果是-使用分析函数和第一排序方法,如果不是-第二排序:
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子句:
顺便说一句,我试图分析你的查询,但它抛出了一些奇怪的错误,我放弃了。在这里,您只需触摸表一次,没有自联接,因此速度应该更快。只添加一个示例数据表就可以替换所有文本,您应该这样做。我添加了两个简单的查询来澄清这一情况。你明白这个问题吗?谢谢编辑问题并添加@TimBiegeleisen询问的样本数据。这样得到好答案的机会就会增加。无论如何,回答你们在评论中提出的问题,NOHi伙计们,我编辑了我的问题,我希望你们现在能理解。谢谢你的需求还没有明确界定。首先,您只显示codigo_origen的1个值—一个糟糕的数据世界,并且对origen->cont进行复杂的优先级排序。这是否意味着如果ORIGON->cont然后排除origen->bkp。从结果来看。此外,您的数据不完整,缺少查询中使用的列campo1和campo2。最后,您使用codigo_origen->contrato 1:1请求唯一行,这意味着什么?数据中似乎没有任何东西可以产生1:1的结果。谢谢你的提问!它做的和我最近发布的查询一样吗?
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