3

我们有一个有数百万条目的表。该表有两列,现在当 X 超出某个值时,X 和 Y 之间存在相关性,Y 趋向于 B(但并非总是如此,它是趋势而不是确定性)。

在这里,我想找到 X 的阈值,即(X1),使得小于 X1 的值的至少 99% 是 B。

可以使用代码轻松完成。但是是否有可以进行计算的 SQL 查询。

对于以下数据集,预期为 6,因为 6 以下超过 99% 是“B”,并且没有更大的 X 值超过 99% 是“B”。但是,如果我将其更改为 90% 的精度,那么它将变为 12,因为如果 X<12 超过 90% 的值是“B”并且没有更大的 X 值适用

所以我们需要找到最大值 X1,使得小于 X1 的值中至少有 99% 是“B”。

X   Y
------
2   B
3   B
3   B
4   B
5   B
5   B
5   B
6   G
7   B
7   B
7   B
8   B
8   B
8   B
12  G
12  G
12  G
12  G
12  G
12  G
12  G
12  G
13  G
13  G
13  B
13  G
13  G
13  G
13  G
13  G
14  B
14  G
14  G
4

3 回答 3

2

好的,我认为这完成了您想要做的事情,但它不适用于您提到的数据量。无论如何,我都会发布它,以防它可以帮助其他人提供答案。

这可能是最有效的方法是使用带有排序数据的游标的情况之一。Oracle 有一些用于相关分析的内置函数,但我从未使用过它,所以我不知道它们是如何工作的。

select max(x)
  from (select x
              ,y
              ,num_less
              ,num_b
              ,num_b / nullif(num_less,0) as percent_b 
          from (select x
                      ,y
                      ,(select count(*) from table b where b.x<a.x) as num_less
                      ,(select count(*) from table b where b.x<a.x and b.y = 'B') as num_b
                  from table a
               )
         where num_b / nullif(num_less,0) >= 0.99
        );

内部选择执行以下操作:

对于 X 的每个值

  • 计算值的 nr < X
  • 计算'B'的nr

下一个 SELECT 计算 B 的比率并仅过滤比率高于阈值的行。外部只是从那些剩余的行中选择 max(x) 。

编辑:上述查询中不可扩展的部分是半笛卡尔自连接。

于 2014-01-23T11:53:33.497 回答
1

这主要是受上一个答案的启发,该答案有一些缺陷。

select max(next_x) from
(
    select 
        count(case when y='B' then 1 end) over (order by x) correct,
        count(case when y='G' then 1 end) over (order by x) wrong,
        lead(x) over (order by x) next_x
    from  table_name
)
where correct/(correct + wrong) > 0.99

样本数据:

create table table_name(x number, y varchar2(1));

insert into table_name
select 2,  'B' from dual union all
select 3,  'B' from dual union all
select 3,  'B' from dual union all
select 4,  'B' from dual union all
select 5,  'B' from dual union all
select 5,  'B' from dual union all
select 5,  'B' from dual union all
select 6,  'G' from dual union all
select 7,  'B' from dual union all
select 7,  'B' from dual union all
select 7,  'B' from dual union all
select 8,  'B' from dual union all
select 8,  'B' from dual union all
select 8,  'B' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 12, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'B' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 13, 'G' from dual union all
select 14, 'B' from dual union all
select 14, 'G' from dual union all
select 14, 'G' from dual;
于 2014-01-23T15:44:30.710 回答
0

试试这个并分享结果:

假设表名为 table_name,列为 x 和 y

with TAB AS (
select (count(x) over (PARTITION BY Y order by x rows between unbounded preceding and current row))/
       (COUNT(case when y='B' then 1 end) OVER (PARTITION BY Y)) * 100 CC, x, y
  from table_name)
select x,y from (SELECT min(cc) over (partition by y) min_cc, x, cc, y
                   FROM TAB
                  where cc >= 99)
where min_cc = cc
于 2014-01-23T12:09:18.493 回答