将列从Varchar2转换为CLOB后,查询无法执行

时间:2016-05-20 08:36:16

标签: oracle11g clob

我有一个oracle查询

int[] child = new int[seledItems.Length];
int[] parent = new int[seledItems.Length];
for(int i = 0; i<seledItems.Length; i++)
{
     string[] parts = seledItems[i].Split('-');
     child[i] = int.Parse(parts[0]);
     parent[i] = int.Parse(parts[1]);
}

LATEST_RECEIPT的数据类型早于varchar2(4000),此查询工作正常。由于列的长度需要扩展,我将其修改为CLOB,之后失败。任何人都可以帮我解决这个问题或提供解决方法吗?

1 个答案:

答案 0 :(得分:1)

您可以更改内部查询以查找具有相同last_receipt值但具有不同ID的其他行(假设ID是唯一的);如果存在另一行,则相当于您的计数返回大于一。但是你不能简单地测试两个CLOB值是否相等,你需要使用dbms_lob.compare

select ID
from your_table t1
where exists (
    select null from your_table t2
    where dbms_lob.compare(t2.LATEST_RECEIPT, t1.LATEST_RECEIPT) = 0
    and t2.ID != t1.ID
    -- or if ID isn't unique: and t2.ROWID != t1.ROWID
);

应用行号过滤器是tricker,因为您也无法在分析partition by子句中使用CLOB。正如AndréSchild所说,你可以使用哈希;这里传递的是整数值3,相当于dbms_crypto.hash_sh1(虽然理论上可以在将来的版本中改变!):

select id from (
    select ID, ROW_NUMBER() over (partition by dbms_crypto.hash(LATEST_RECEIPT, 3)
        order by ID) rownumber
    from your_table t1
    where exists (
        select null from your_table t2
        where dbms_lob.compare(t2.LATEST_RECEIPT, t1.LATEST_RECEIPT) = 0
        and t2.ID != t1.ID
        -- or if ID isn't unique: and t2.ROWID != t1.ROWID
    )
)
where rownumber > 1;

当然可能会发生哈希冲突,如果发生了这种情况 - 你有两个latest_receipt值,它们都出现过多次并且都散列到相同的值 - 那么你可能会得到太多的行。这似乎不太可能,但需要考虑。

因此,您只能查找具有相同lastest_receipt和较低ID的行,而不是订购:

select ID
from your_table t1
where exists (
    select null from your_table t2
    where dbms_lob.compare(t2.LATEST_RECEIPT, t1.LATEST_RECEIPT) = 0
    and t2.ID < t1.ID
);

再次假设ID是唯一的。如果不是,那么您仍然可以使用rowid代替,但您可以较少控制找到哪些行 - 最低rowid不一定是最低ID。据推测,您正在使用此功能来删除行。如果您实际上不介意保留哪一行以及删除哪一行,那么您仍然可以这样做:

and t2.ROWID < t1.ROWID

但是,由于您目前的订购可能是不可接受的,并且尽管风险很小,但散列可能更可取。