2016-05-20 6 views
1

У меня есть запрос оракулазапросов не может выполнить после преобразования столбца из varchar2 в Clob

select id from (
    select ID, ROW_NUMBER() over (partition by LATEST_RECEIPT order by ID) rownumber 
    from Table 
    where LATEST_RECEIPT in 
    (
     select LATEST_RECEIPT from Table 
     group by LATEST_RECEIPT 
     having COUNT(1) > 1 
    ) 
) t 
where rownumber <> 1; 

Тип данных LATEST_RECEIPT был ранее varchar2 (4000), и этот запрос работал нормально. Поскольку длина столбца должна быть расширена, я изменил ее на CLOB, после чего это не удалось. Может ли кто-нибудь помочь мне исправить эту проблему или обеспечить работу?

+1

Какая ошибка возникает? –

+0

ORA00932- несогласованный тип данных - ожидается: получено clob – Vasanthan

+3

Это один из недостатков использования CLOB/BLOB, они не могут использоваться для индексов, а затем также не для функций GROUP BY и других функций agregate. Я думаю, вам придется преобразовать его обратно в тип данных VARCHAR (гораздо больше). –

ответ

1

Вы можете изменить свой внутренний запрос, чтобы искать другие строки с тем же значением last_receipt, но другой идентификатор (при условии, что идентификатор уникален); если существует еще одна строка, то это эквивалентно тому, что ваш счет возвращается больше одного. Но вы не можете просто проверить два значения 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, так как вы не можете использовать CLOB в аналитическом partition by пункте. Как предложил Андре Шильд, вы можете использовать хэш; здесь проходит целое значение 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 
); 

Опять же, что предполагает идентификатор уникален. Если это не так, вы все равно можете использовать rowid, но у вас будет меньше контроля над тем, какие строки были найдены - самый низкий rowid не обязательно самый низкий идентификатор. Предположительно, вы используете это, чтобы обедать строки для удаления. Если вы на самом деле не против какой строке вы держите, и которые вы удаляете, то еще можно было сделать:

and t2.ROWID < t1.ROWID 

Но так как вы в настоящее время заказа, что, вероятно, не является приемлемым, и хеширования может быть предпочтительным, несмотря на малый риск.