2016-11-12 6 views
0

У меня есть таблица с столбцами C1, C2, C3, C4, C5, C6 и Count. Я должен заказать записи, используя порядок по C1, C2, C3, C4, C5. Для первой записи Count будет 0, если значения C1, C2, C3, C4, C5 следующей строки совпадают с предыдущей строкой, тогда я должен обновить столбец Count, добавив +1. Так это то, что я ожидал: Таблица:Обновление столбца на основе предыдущей записи

C1 C2 C3 C4 C5 C6  Count 
------------------------------------------- 
1 A  X  X1 AA 123  0 
1 A  X  X1 AA 121  1 
1 A  X  X1 AA 118  2 
1 A  X  X1 AA 117  3 
2 B  X  X2 AA 234  0 
8 A  Y  X3 AA 298  0 
8 A  Y  X3 AA 800  1 

Я использую Oracle DB. Я написал блок PL SQL с курсором с Order by, а затем использовал курсор в BULK COLLECT и повторил каждую запись по сравнению с предыдущей записью. Однако столбец Count обновляется с неожиданной записью и занимает гораздо больше времени, чем ожидалось, таблица имеет около 400 тыс. Записей. Я не могу ввести свой код здесь, поскольку фактический код находится в клиентской машине. Любая помощь высоко ценится. Можно использовать PL/SQL или Simple SQL. DB - это Oracle.

+0

Зачем вам нужно писать блок PL/SQL с помощью курсора BULK COLLECT и перебирать каждую строку и т. Д.? Изучение правильного способа сделать это в простом SQL намного проще и эффективнее - и для изучения правильного SQL для этого требуется гораздо меньше времени, чем для изучения PL/SQL. Тогда: Зачем вам нужен заказ «count» в таблице? Это имеет смысл в представлении или в запросе для создания отчета; ХРАНЕНИЕ его в таблице может вызвать проблемы в будущем. Что делать, если строка удаляется в будущем, или C3 корректируется с Y на X? Теперь вам нужно пересчитать весь столбец! Плохая идея. – mathguy

ответ

1

Я считаю, что вы хотите row_number():

select t.*, 
     (row_number() over (partition by c1, c2, c3, c4, c5 order by c6) - 1 
     ) as "Count" 
from t; 

Вы можете использовать merge поместить это в update заявлении. С другой стороны, если вы действительно хотите update:

update t 
    set count = (select count(*) 
       from t t2 
       where t2.col1 = t.col1 and t2.col2 = t.col2 and t2.col3 = t.col3 and 
         t2.col4 = t.col4 and t.col5 = t2.col5 and 
         t2.col6 < t.col6 
       ); 
+0

Спасибо. Используя ваш запрос, я могу взломать проблему. – Sid

+0

Нет никакой рифмы или причины для заказа от col6, не уверен, заметили ли вы. OP показывает увеличение «count» для упорядочения DESC на col6 в случае (A, X), но затем для упорядочения ASC на col 6 в случае (A, Y). Наверное, не стоит больше смотреть на нее, поскольку все назначение действительно бессмысленно. – mathguy

0

С помощью намека предоставленного Гордона Линофф я могу решить эту проблему. Однако, чтобы избежать проблем с производительностью, я создал новую таблицу вместо обновления. Ниже приведен запрос:

CREATE TABLE TAB2 AS 
SELECT T1.C1, T1.C2, T1.C3, T1.C4, T1.C5, T1.C6, T1.REC_COUNT 
(select t.*, 
     (row_number() over (partition by c1, c2, c3, c4, c5 order by c1, c2, c3, c4, c5) - 1 
     ) as rec_count 
from tab1 T) T1; 
+0

Заказ по тем же столбцам, что и разделы, разделяемые (или их подмножеством), приводит к случайному упорядочению - что, как вам кажется, в любом случае; нет очевидной логики в представленном вами заказе с фиксированными c1-c5. (Причина, по которой у вас есть заказ, - «случайный», заключается в том, что он находится внутри каждого раздела, в котором c1-c5 фиксированы для всех строк в разделе.) Вы получаете точно такой же (случайный) результат, опуская «order by c1 , ..., c5 "из аргументов row_number(). Просто сохраните раздел по частям. – mathguy

Смежные вопросы