Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Oracle > Способы подсчёта строк(какие есть)


Автор: NetShadow 12.3.2007, 23:01
Собственно сабж такой, есть какие-то ещё способы подсчёта строк в Oracle, я знаю rownum и count(), а есть другие, в delphi DBGrid выводится результат запроса, туда можно добавлять строки, но их не должно быть больше 6-ти, если шесть то запрещать insert... smile 

Автор: LSD 13.3.2007, 00:51
Если тебе нужно запрещать insert более шести записей в таблицу, то без блокировок этой таблицы, на уровне сервера, не обойтись.

Автор: Sqlninja 13.3.2007, 10:47
Я так понял, что речь идет о контроле поведения визуального компонента. Тогда это лучше сделать средствами самого Delphi. Даже если это после коммита происходит, лучше не гонять туда-сюда сетевой трафик, а считать какое нибудь клиентское свойство типа Dataset.Rowcount.

Автор: NetShadow 13.3.2007, 20:28
спасибо всем кто пытался помочь, проблема была решена добавлением кода к триггеру на событие before update, insert...код примерно такой: 
Код

begin
 select count(*) into numrows from table t, table1 t1
 where t.index=t1.index1;
   if numrows=6 then
     Class_Message('Ошибка, не возможно добавить более 6 параметров');
   endif; 
end;
 

Автор: LSD 13.3.2007, 22:27
Это не сработает, если вставка будет идти из разных сессий.

Автор: Тиль 14.3.2007, 10:18
Триггре на insert  в таблицу не пробовал?

Автор: DimW 14.3.2007, 11:36
Цитата(Тиль @  14.3.2007,  10:18 Найти цитируемый пост)
Триггре на insert  в таблицу не пробовал?


Цитата(NetShadow @  13.3.2007,  20:28 Найти цитируемый пост)
проблема была решена добавлением кода к триггеру на событие before update, insert...

но это не подходит для многосессионной рабыты с таблицами.
о чем и говорил LSD.

Цитата(LSD @  13.3.2007,  22:27 Найти цитируемый пост)
Это не сработает, если вставка будет идти из разных сессий.


красивого решения пока нет, но кое что накидал.
изврат №1(организовать вставку позиций в таблицу припомоши процедуры):
Код

declare 
  cursor c1 is 
    select id 
       from hr_emp
     for update nowait;
  n number:=0;
begin
  for i in c1 
  loop 
    n := n + 1; 
  end loop;
  if n = 6 then
    raise_application_error(-20000, 'не больше 6-ти записей в татлицу....');
  else
   insert ...     
  end if;
end;

вобщем это не процедура, но идея понятна (for update nowait)...
единственное что меня смущает в этом решении так это пробежка по курсору для подсчета количества позиций.

изврат №2:
если первичный ключ организован по сиквенсу то можно задать сиквенсу мин. и макс. значение нужного диапазона в нашем случае от 1..6. тогда при следеющем sq.nextval будет вываливаться ошибка о том что нельзя получить следеющее значение сиквенса, которую можно отловить и по русски сказать юзеру что он не прав...
этот способ мне нравиться больше, но я не знаю есть ли потенциальные баги в этом способе, за иключением одного - если какой нить моньяк не увеличит макс. значение сиквенса.

над третьим извратом пока думаю, так сказать изучаю возможности dbms_lock ...

Автор: LSD 14.3.2007, 12:42
А как во втором способе обработать удаление строк?

Автор: DimW 14.3.2007, 12:53
Цитата(LSD @  14.3.2007,  12:42 Найти цитируемый пост)
А как во втором способе обработать удаление строк? 


а ни как  smile (если конечно не запретить удаление на клиенте...)
второй способ на свалку...

Автор: DimW 14.3.2007, 15:06
вобщем начитался про dbms_lock и вот что получилось:
создадим табличку для проверки.

Код

create table TEST_01
(
  NAME NUMBER
)
/

убедимся что у нас есть привилегия EXECUTE на пакет DBMS_LOCK. И тестим.

Код

declare 
  n number := 0;
begin
  if (dbms_lock.request(id => 1, -- это идентификатор блока, может быть произвольным, но должен соответствовать типу integer
                        lockmode => dbms_lock.x_mode,
                        timeout => 0,
                        release_on_commit => true) = 1) then
    -- если блок стоит то вызываем ошибку                    
    raise_application_error(-20000, 'таблица занята другим пользователем...');
  else -- если блок не стоит то считаем записи в таблице
    select count(name)
      into n
      from TEST_01;
    if n = 6 then -- если записей 6 то вызываем ошибку
      raise_application_error(-20001, 'не больше 6-ти записей в татлицу....');
    else -- если не шесть то разрешаем вставку позиции (предпологается что записей до использования етого миханизма было меньше шести)
      insert into TEST_01
             (name)
      values (10);     
    end if;
  end if;
end;

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

NetShadow, а теперь можно узнать нафига тебе это нужно(не больше 6 записей в таблице )?  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)