Можете ли вы проверить, существует ли столбец и выполнить различные действия с оракулом? - PullRequest
0 голосов
/ 28 декабря 2018

Моя таблица выглядит следующим образом:

id | value1 | count

У меня есть список value1 в оперативной памяти, и я хочу сделать следующее:

    (if value1 exists in table){
    count + 1}else{
    insert new row into table}

Возможно ли это сOracle или мне нужно взять его в код, сделать for loop и выполнить по одному элементу списка за раз?Список содержит 5 миллионов значений.Мне нужно сделать что-то вроде этого в коде:

for(int i=0; i<list.size; i++){
  boolean exists = checkifexists(list.get(i));
  if(exists=true){
    countPlusOne(list.get(i);
  }else{
    createNewRow(list.get(i));
  }
}

Так что мне нужно сделать по крайней мере два запроса для каждого значения, всего 10 миллионов + запросов.Это может занять много времени и, возможно, не самый эффективный способ сделать это.Я пытаюсь придумать другой способ.

Ответы [ 4 ]

0 голосов
/ 28 декабря 2018

«Я загружаю их в оперативную память из базы данных»

У вас уже есть исходные данные в базе данных, поэтому вы должны выполнить обработку в базе данных.Создание списка из 5 миллионов строк в локальной памяти не является дешевой операцией, особенно когда это не нужно.

Oracle поддерживает функцию MERGE, которую мы можем использовать для проверки существования записи в целевой таблице и заполнения новойстрока условно.Будучи заданной операцией, MERGE гораздо более эффективен, чем вставка одной строки в цикл Java.

Хитрость - это уникальность.Вам необходимо получить управляющий запрос из исходной таблицы, которая содержит уникальных значений (в противном случае MERGE будет отбрасывать).В этом примере я агрегирую количество каждого вхождения value1 в исходной таблице.Это дает нам набор value1 плюс цифру, которую мы можем использовать для поддержания столбца count в целевой таблице.

merge into you_target_table tt
using ( select value1
               , count(*) as dup_cnt
        from your_source_table
        group by value1
      ) st
on ( st.value1 = tt.value1 )
when not matched then
   insert (id, value1, cnt) 
   values (someseq.nextval, st.value1, st.dup_cnt)
when matched then
   update
   set tt.cnt = tt.cnt + st.dup_cnt;

(я предполагаю, что столбец ID целевой таблицы заполненпоследовательность, измените это, как вам требуется).

0 голосов
/ 28 декабря 2018

В Oracle мы могли бы использовать оператор MERGE, чтобы проверить, существует ли строка, и выполнить вставку, только если ее нет.

Сначала создайте тип, который определяет ваш список.

CREATE OR REPLACE TYPE value1_type as TABLE OF VARCHAR2(10); --use the datatype of value1

Оператор слияния.

MERGE INTO yourtable t 
USING (
   select distinct column_value as value1 FROM TABLE(value1_type(v1,v2,v3))
)s ON ( s.value1 =  t.value1 )
WHEN NOT MATCHED THEN INSERT
(col1,col2,col3) VALUES ( s.col1,s.col2,s.col3);

Вы также можете использовать NOT EXISTS.

INSERT INTO yourtable t 
select * FROM 
(
  select distinct column_value as value1 from  TABLE(value1_type(v1,v2,v3))
) s
      WHERE NOT EXISTS
    (
      select 1 from
       yourtable t where t.value1 = s.value1 
    );
0 голосов
/ 28 декабря 2018

Сначала заполните свой список ОЗУ во временной таблице TMP

select * from tmp; 
VALUE1    
----------
V00000001
V00000002
V00000003
V00000004
V00000005
...

Вы можете использовать оператор MERGE для обработки вашего логика

  • , если ключ существует, увеличитьсчитать на 1
  • , если ключ не существует, вставить его с начальным счетом 1

.

merge into val
using tmp
on (val.value1 = tmp.value1)
when matched then update
   set val.count = val.count + 1
when not matched then
   insert (val.value1, val.count)
   values (tmp.value1, 1)
;

Обратите внимание, что у вас есть IDENTITY введите в столбце ID, поэтому назначение ключа не требуется.

В случае дублирования записи в таблице TMP (больше записей с одинаковым ключом VALUE1) вы получаете ошибку, поскольку MERGE не может выполнять больше действий одним ключом.

 ORA-30926: unable to get a stable set of rows in the source tables

Если вы хотите считать каждый дублированный ключ как один - вы должны предварительно агрегировать временную таблицу, используя GROUP BY идобавьте counts.

В противном случае просто игнорируйте дубликаты, используя DISTINCT.

merge /*+ PARALLEL(5) */ into val
using (select value1, count(*) count from tmp group by value1) tmp
on (val.value1 = tmp.value1)
when matched then update
   set val.count = val.count + 1
when not matched then
   insert (val.value1, val.count)
   values (tmp.value1, 1)
0 голосов
/ 28 декабря 2018

Вы можете сделать это двумя способами

Подход 1:

  1. Создать временную таблицу в базе данных и вставить все свои значения в ОЗУ в эту временную таблицу
  2. Напишите запрос на обновление счетчика на основе соединения вашей основной таблицы и временной таблицы и установите флаг во временной таблице, значения которого обновляются, значение, которое не обновляется, использует запрос вставки для вставки.

Подход 2:

  1. Вы можете создать свой собственный тип данных, который принимает массив значений в качестве входных данных: CREATE OR REPLACE TYPE MyType AS VARRAY(200) OF VARCHAR2(50);
  2. Вы можете написать процедуру с вашей логикой, процедура примет значениемассив в качестве ввода: CREATE OR REPLACE PROCEDURE testing (t_in MyType)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...