Как? Правильный синтаксис sql для поиска следующего доступного идентификатора - PullRequest
1 голос
/ 16 декабря 2010

Я думаю, что я мог бы получить помощь от более опытных пользователей ... У меня есть целочисленное имя поля в таблице, давайте назовем его SO_ID в таблице SO, и для каждой новой строки мне нужно вычислить новый SO_ID на основе следующих правил
1) SO_ID состоит из 6 букв, где первые 3 - это код города, а последние три - порядковый номер в этой области.
309001
309002
309003
2) поэтому следующая новая строка будет иметь SO_ID со значением
309004
3) если кто-то удаляет строку со значением SO_ID = 309002, то следующая новая строка должна перерабатывать это значение, поэтому следующая строка должна иметь SO_ID со значением
309002

Может ли кто-нибудь предоставить мне функцию SQL или PL / SQL (возможно, сразу триггер?), Которая будет возвращать следующий доступный SO_ID, который мне нужно использовать? Я полагаю, я мог бы использовать ключевое слово rownum в моем sql, но следующее просто не работает должным образом

select max(so_id),max(rownum)   from( 
select (so_id),rownum,cast(substr(cast(so_id as varchar(6)),4,3) as int) from SO 
where length(so_id)=6  
and substr(cast(so_id as varchar(6)),1,3)='309' 
and cast(substr(cast(so_id as varchar(6)),4,3) as int)=rownum 
order by so_id 
);

спасибо за вашу помощь!

Ответы [ 6 ]

6 голосов
/ 17 декабря 2010

Такая логика таит в себе опасность. Что если два сеанса вычисляют одно и то же «следующее» значение или оба пытаются повторно использовать одно и то же «удаленное» значение? Поскольку ваш столбец является целым числом, вам, вероятно, будет лучше запросить «между 309001 и 309999», но возникает вопрос о том, что произойдет, когда вы попадете в тысячный элемент в области 309?

Можно ли сделать SO_ID внешним ключом для другой таблицы, а также уникальным ключом? Вы можете предварительно заполнить родительскую таблицу всеми действительными идентификаторами (или использовать функцию для их генерации по мере необходимости), и тогда будет просто выбрать самую нижнюю, где дочерняя запись не существует.

1 голос
/ 17 декабря 2010

хорошо, мы придумали этот ... вид работ .. параллелизм 'решается' с помощью уникального ограничения

select min(lastnumber)
from
(
select so_id,so_id-LAG(so_id, 1, so_id) OVER (ORDER BY so_id) AS diff,LAG(so_id, 1, so_id) OVER (ORDER BY so_id)as lastnumber 
from so_miso
where substr(cast(so_id as varchar(6)),1,3)='309'
and length(so_id)=6
order by so_id
)a 
where diff>1;
0 голосов
/ 17 декабря 2010

Игнорируя проблемы с параллелизмом, следующее должно дать достойное начало.Если «трафик» на таблице достаточно низкий, продолжайте блокировку таблицы в эксклюзивном режиме на время транзакции.

create table blah (soc_id number(6));
insert into blah select 309000 + rownum from user_tables;
delete from blah where soc_id = 309003;
commit;

create or replace function get_next (i_soc in number) return number is
  v_min number := i_soc* 1000;
  v_max number := v_min + 999;
begin
  lock table blah in exclusive mode;
  select min(rn) into v_min 
    from
    (select rownum rn from dual connect by level <= 999
    minus
    select to_number(substr(soc_id,4))
    from blah
    where soc_id between v_min and v_max);
  return v_min;
end;
0 голосов
/ 17 декабря 2010

Если вы перезагружаете числа при удалении строк, при создании следующего числа необходимо обращаться к вашей базовой таблице. «Устаревшие» до-реляционные схемы, которые пытаются кодировать информацию в числах, являются труднодостижимыми, когда числа должны быть переработаны после удаления, как вы говорите, ваши.

Если вы не хотите сканировать таблицу на наличие пробелов, подпрограмма после удаления должна записать удаленный номер в отдельную таблицу в столбце «ReuseMe». Процедура вставки делает это:

      begins trans
         selects next-number table for update
         uses a reuseme number if available else uses the next number
         clears the reuseme number if applicable or increments the next-number in the next-number table
       commits trans
0 голосов
/ 16 декабря 2010

Если ваше приложение не является чистым SQL, вы можете сделать это в коде приложения (то есть: код Java). Это было бы более простым.

0 голосов
/ 16 декабря 2010

Вам действительно нужно вычислить и сохранить это значение во время вставки строки? Обычно было бы лучше сохранить код города и дату в таблице и вычислить SO_ID в представлении, т.е.

SELECT area_code || 
           LPAD( DENSE_RANK() OVER( PARTITION BY area_code 
                                        ORDER BY date_column ), 
                 3, 
                 '0' ) AS so_id,
       <<other columns>>
  FROM your_table

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

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