Как обновить столбец, используя select в Oracle - PullRequest
3 голосов
/ 27 июня 2019

У меня есть требование обновить значение ID2 столбца в таблице на основе Name & DOB.Я создал последовательность оракула и решил заполнить значение в столбце ID2, но не могу объединить логику в запросе на обновление.Пожалуйста, посмотрите мой код ниже, в котором я собирался сделать группу на Name, DOB и обновить ID2, но я застрял в середине в логике.если у вас есть какое-либо решение в sql или plsql, то оно работает!Спасибо.

CREATE SEQUENCE seq
  MINVALUE 1
  START WITH 100
  INCREMENT BY 1;


UPDATE table1 SET ID2 = seq.nextval
where Name= ---NOT SURE WHAT TO DO ?
select count(*) from table1
group by NAME,DOB;

enter image description here

1 Ответ

1 голос
/ 27 июня 2019

Предполагая, что значения ID2 должны быть в том же порядке, что и значения ID1, и нет повторяющихся значений ID1, вы можете сделать это без последовательности, используя аналитические функции с подходящими предложениями окна:

select name, dob, id1,
  100 + dense_rank() over (order by trunc(id1))
      + dense_rank() over (partition by trunc(id1) order by id1)/10
      as id2
from table1;

NAME  DOB               ID1        ID2
----- ---------- ---------- ----------
JIM   1991-11-30       23.1      101.1
JIM   1991-11-30       23.2      101.2
JIM   1991-11-30       23.3      101.3
TOM   1993-12-30       30.1      102.1
TOM   1993-12-30       30.2      102.2
HENRY 1994-12-03       34.1      103.1
HENRY 1994-12-03       34.2      103.2

7 rows selected. 

Затем вы можете использовать эту сгенерированную таблицу как часть оператора слияния:

merge into table1
using (
  select name, dob, id1,
    100 + dense_rank() over (order by trunc(id1))
        + dense_rank() over (partition by trunc(id1) order by id1)/10
        as id2
  from table1
) tmp on (tmp.id1 = table1.id1)
when matched then
update set table1.id2 = tmp.id2;

7 rows merged.

select * from table1;

NAME  DOB               ID1        ID2
----- ---------- ---------- ----------
JIM   1991-11-30       23.1      101.1
JIM   1991-11-30       23.2      101.2
JIM   1991-11-30       23.3      101.3
TOM   1993-12-30       30.1      102.1
TOM   1993-12-30       30.2      102.2
HENRY 1994-12-03       34.1      103.1
HENRY 1994-12-03       34.2      103.2

7 rows selected. 

db <> fiddle

Если ID2 не нужнобыть связанным с ID1, вы можете заказать по своему усмотрению:

merge into table1
using (
  select name, dob, id1,
    100 + dense_rank() over (order by name, dob)
        + dense_rank() over (partition by name, dob order by id1)/10
        as id2
  from table1
) tmp on (tmp.id1 = table1.id1)
when matched then
update set table1.id2 = tmp.id2;

select * from table1;

NAME  DOB               ID1        ID2
----- ---------- ---------- ----------
JIM   1991-11-30       23.1      102.1
JIM   1991-11-30       23.2      102.2
JIM   1991-11-30       23.3      102.3
TOM   1993-12-30       30.1      103.1
TOM   1993-12-30       30.2      103.2
HENRY 1994-12-03       34.1      101.1
HENRY 1994-12-03       34.2      101.2

Это будет работать как есть, только если десятичная дробь не будет больше 0,9;но тогда было бы трудно интерпретировать значения, если бы это произошло (поскольку 23.10 - это то же самое, что и 23.1).

Я также предполагаю, что это разовое обновление, и вы не• планируют использовать последовательность для будущих вставок;непонятно, как бы вы справились с этим - вы бы хотели получить следующее значение последовательности, только если имя / DOB еще не существует, и если бы они это сделали, вам нужно было бы найти самый высокий существующий идентификатор и добавить к нему 0,1,В любом случае вам нужно было бы сериализовать вставки для предотвращения столкновений или расхождений.

это фактически привело к ситуации, когда значение ID1 было 23,10, 23,11, а ID2 отображало их как 101,1, 101,1.... Я попытался разделить его на 100, и проблема была решена для значения> = .11 десятичных знаков, но для .10 и .20 он по-прежнему отображается как .1 & .2.

Это говорит о том, чтооба значения ID являются строковыми, а не числами.Если это так, вы все равно можете использовать функции ранжирования, но обрабатывать два сгенерированных числа как строки и объединять их вместе:

    merge into table1
    using (
      select name, dob, id1,
        to_char(100 + dense_rank() over (order by name, dob))
            ||'.'||
            dense_rank() over (partition by name, dob
              order by to_number(substr(id1, instr(id1, '.') + 1)))
            as id2
      from table1
    ) tmp on (tmp.id1 = table1.id1)
    when matched then
    update set table1.id2 = tmp.id2;

With some additional base data that gives you:

select * from table1;

NAME  DOB        ID1        ID2       
----- ---------- ---------- ----------
JIM   1991-11-30 23.1       103.1     
JIM   1991-11-30 23.2       103.2     
JIM   1991-11-30 23.3       103.3     
TOM   1993-12-30 30.1       104.1     
TOM   1993-12-30 30.3       104.2     
HENRY 1993-12-30 34.1       101.1     
HENRY 1994-12-03 34.5       102.1     
HENRY 1994-12-03 34.6       102.2     
HENRY 1994-12-03 34.7       102.3     
HENRY 1994-12-03 34.8       102.4     
HENRY 1994-12-03 34.9       102.5     
HENRY 1994-12-03 34.10      102.6     
HENRY 1994-12-03 34.11      102.7     
HENRY 1994-12-03 34.12      102.8     
HENRY 1994-12-03 34.13      102.9     
HENRY 1994-12-03 34.14      102.10    
HENRY 1994-12-03 34.15      102.11    
HENRY 1994-12-03 34.16      102.12    

db <> fiddle

Конечно,выполнение этого делает невозможным очень неудобное обращение со значениями ID2 как с числами или их упорядоченное упорядочение;но тогда это должно иметь место уже для ваших значений ID1.В качестве альтернативы можно вместо этого умножить первую часть на большое число, скажем, 1000, а затем добавить вторую часть, чтобы Генри закончил с 1020001 до 1010012.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...