Как можно обновить столбец на основе значения другого столбца в SQL?

В основном у меня есть таблица продукта, как это:

date       price
---------  -----
02-SEP-14     50  
03-SEP-14     60  
04-SEP-14     60  
05-SEP-14     60  
07-SEP-14     71  
08-SEP-14     45  
09-SEP-14     45  
10-SEP-14     24  
11-SEP-14     60

Мне нужно обновить таблицу в этой форме

date       price   id
---------  -----   --
02-SEP-14     50    1
03-SEP-14     60    2
04-SEP-14     60    2
05-SEP-14     60    2
07-SEP-14     71    3
08-SEP-14     45    4
09-SEP-14     45    4
10-SEP-14     24    5
11-SEP-14     60    6

Что я пробовал:

CREATE SEQUENCE user_id_seq
  START WITH 1
  INCREMENT BY 1
  CACHE 20;

ALTER TABLE Product
  ADD (ID number);

UPDATE Product SET ID = user_id_seq.nextval;

Это обновляет идентификатор обычным способом, как 1,2,3,4,5..

Я понятия не имею, как это сделать, используя основные команды SQL. Подскажите пожалуйста как мне это сделать. Заранее спасибо.

4 ответа

Решение

Вот один из способов создать представление из ваших базовых данных. Я предполагаю, что у вас есть более одного продукта (идентифицируемого по идентификатору продукта), и что даты цен не обязательно являются последовательными. Последовательность является отдельной для каждого идентификатора продукта. (Также, product должно быть именем другой таблицы - где идентификатор продукта является первичным ключом, а у вас есть другая информация, такая как название продукта, категория и т. д. Таблица в вашем сообщении будет более правильно называться примерно так: price_history.)

alter session set nls_date_format='dd-MON-rr';

create table product ( prod_id number, dt date, price number );

insert into product ( prod_id, dt, price )
  select 101, '02-SEP-14', 50 from dual union all 
  select 101, '03-SEP-14', 60 from dual union all  
  select 101, '04-SEP-14', 60 from dual union all 
  select 101, '05-SEP-14', 60 from dual union all 
  select 101, '07-SEP-14', 71 from dual union all  
  select 101, '08-SEP-14', 45 from dual union all 
  select 101, '09-SEP-14', 45 from dual union all 
  select 101, '10-SEP-14', 24 from dual union all 
  select 101, '11-SEP-14', 60 from dual union all
  select 102, '02-SEP-14', 45 from dual union all
  select 102, '04-SEP-14', 45 from dual union all
  select 102, '05-SEP-14', 60 from dual union all
  select 102, '06-SEP-14', 50 from dual union all
  select 102, '09-SEP-14', 60 from dual
;

commit;

create view product_vw ( prod_id, dt, price, seq ) as
  select prod_id, dt, price, 
         count(flag) over (partition by prod_id order by dt)
  from   ( select prod_id, dt, price,
                  case when price = lag(price) over (partition by prod_id order by dt)
                       then null else 1 end as flag
           from   product
         )
;

Теперь проверьте, как выглядит вид:

select * from product_vw;

PROD_ID DT                       PRICE        SEQ
------- ------------------- ---------- ----------
    101 02/09/0014 00:00:00         50          1
    101 03/09/0014 00:00:00         60          2
    101 04/09/0014 00:00:00         60          2
    101 05/09/0014 00:00:00         60          2
    101 07/09/0014 00:00:00         71          3
    101 08/09/0014 00:00:00         45          4
    101 09/09/0014 00:00:00         45          4
    101 10/09/0014 00:00:00         24          5
    101 11/09/0014 00:00:00         60          6
    102 02/09/0014 00:00:00         45          1
    102 04/09/0014 00:00:00         45          1
    102 05/09/0014 00:00:00         60          2
    102 06/09/0014 00:00:00         50          3
    102 09/09/0014 00:00:00         60          4
WITH cts AS  
(
SELECT row_number() over (partition by price order by price ) as id
,date
,price  
FROM Product 
)
UPDATE p
set p.id = cts.id 
from product p join cts on cts.id = p.id

ПРИМЕЧАНИЕ: это отвечает на вопрос, который был первоначально задан. ОП изменил данные.

Если ваши данные не слишком велики, вы можете использовать коррелированный подзапрос:

update product p
    set id = (select count(distinct p2.price)
              from product p2
              where p2.date <= p.date
             );

Если ваши данные больше, то merge более уместно.

Это лучший способ, которым вы пытаетесь сделать. Нет другого простого способа сделать это с помощью простых утверждений

Другие вопросы по тегам