Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 17.04.2009, 23:43   #1
FReeMAN(Q)
Подтвердите свой е-майл
 
Регистрация: 13.04.2009
Сообщений: 8
Вопрос SQL: как присвоить записи её порядковый номер?

Вопрос в следующем есть таблица.. в ней некоторое число записей..
необходимо при создании новой записи автоматически присвоить ей следующий порядковый номер..
Как я понимаю для этого просто надо посчитать количество записей полученный ответ увеличить на еденицу и записать в поле новой записи..
в SQL количество считает COUNT() но кауда он записывает результат? и как направить этот результат в переменную.. подскажите..
с таблицей работаю через Query...
FReeMAN(Q) вне форума Ответить с цитированием
Старый 18.04.2009, 07:54   #2
Скандербег
Форумчанин
 
Регистрация: 04.04.2009
Сообщений: 438
По умолчанию

Можно себе представить беднягу пользователя, работающего с такой базой.
При каждом добавлении записи сидит и ждет, когда же сервер посчитает сколько там этих записей, если таблица имеет миллионы строк.
А если серьезно, то такой алгоритм не годится, если нужны уникальные номера записей.
На примере. Есть две записи под номерами 1 и 2. Удаляем первую запись потом добавляем еще одну. В результате обе записи будут иметь один и тот же номер - 2. Так годится?
Чтобы ответить на этот вопрос необходимо знать как используются (или предполагается использовать) присвоенные номера записей.
В SQL базах, где действительно требуются уникальные номера (идентификаторы) записей получение такого ИД уже давным-давно автоматизировано.

Результат запроса select count(*) from <имя таблицы> возвращается в том же DataSet (Query, например), который отправил запрос.
А "...направить этот результат в переменную" можно так:
Код:
   CntRec := Query.FieldByName('COUNT').AsInteger;

Последний раз редактировалось Скандербег; 18.04.2009 в 08:12.
Скандербег вне форума Ответить с цитированием
Старый 18.04.2009, 09:44   #3
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Скандербег, +1
полностью согласен.

FReeMAN(Q),
1) есть такой тип поля, как autoincrement (счётчик)
тогда сама СУБД будет наращивать счётчик при записи в базу
2) в нормальных СУБД ещё есть такое понятие как генератор последовательностей (SEQUENCE)
(результаты поиска на гугл)
3) Если СУБД это не предусматривает — например, FoxPro for DOS - тогда оптимальный способ держать отдельно табличку, где хранить имя таблицы и текущий доступный код. Надо добавить запись - открывает эту вспогательную табличку, находим там запись для нашей таблицы, лочим(блокируем) запись (чтобы не было конфликтов при одновременной многопользовательской работе по добавлению данных), наращиваем счётчик, записываем новое значение в эту вспомогательную таблицу, разблокируем запись, и добавляем новую запись в таблицу со взятым значением счётчика.

и последнее, если таблица маленькая (или учебная задача) и со всем вышеуказанным заморачиваться не хочется, тогда, всё же лучше вместо количества записей брать максимальное значение счётчика:
Код:
  ADOQuery1.Close;
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select MAX(Код) as MaxCode from Tablica1');
  ADOQuery1.Open;
  if  ADOQuery1.IsEmpty then NextCode := 1
  else NextCode := ADOQuery1.FieldByName('MaxCode').AsInteger + 1;
  ADOQuery1.Close;
{всё можно добавлять новую запись с кодом NextCode}
но учтите, Скандербег абсолютно прав, если добавление идёт интенсивно и часто, а база достаточно большая - то нагрузка на БД по получению максимального кода может быть весьма большой. Хотя, конечно, индексы (а по ключевому полю они просто обязаны быть!) сильно улучшают ситуацию. Но всё таки, имейте это в виду!
Serge_Bliznykov вне форума Ответить с цитированием
Старый 18.04.2009, 10:10   #4
FReeMAN(Q)
Подтвердите свой е-майл
 
Регистрация: 13.04.2009
Сообщений: 8
Вопрос

нужно что бы полю Pnom присваивался порядковый номер записи и что бы при удалении например записи с порядковым номером (Pnom) 5 этот порядковый номер присваивался записи вставшей на её место... все просто.. но чего то не выходит..


Код:
procedure TForm2.Button1Click(Sender: TObject);

var
i,cena,cntrec:integer;
 dt,vd,mst,op,rek:string;

begin


i:=combobox1.ItemIndex;
dt:= DateToStr( Date );
vd:= combobox1.Items.Strings[i];
cen:= StrToInt(edit1.Text);
mst:= edit2.Text;
op:=  edit3.Text;
rek:= edit4.Text;

if form1.ComboBox3.ItemIndex=0
then
begin

cntrec:=form1.Query2.fieldbyname('pnom').AsInteger;
cntrec:=cntrec+1;


form1.query2.Active:=false;
form1.Query2.SQL.Clear;
form1.Query2.SQL.Add('insert into pokupka (Pnom, Dat, Vid, Cena, Mesto, Opis, Rekvizit)');

form1.Query2.SQL.Add('values ('+inttostr(Cntrec)+', '''+dt+''', '''+vd+''', '+inttostr(cen)+', '''+mst+''', '''+op+''', '''+Rek+''' )');
form1.Query2.ExecSQL;

form1.Query2.SQL.Clear;
form1.Query2.SQL.Add('select * from pokupka');
form1.Enabled:=true;
form1.TabbedNotebook1.ActivePage:='Покупка';
form1.query2.Active:=true;

form2.Close;

end;
end;
он вводит в номер записи одно и то же число...
видимо я не догоняю как правильно втыкнуть счетчик..

P.S.: и все же как при удаленнии одной записи присваивать остальным их порядковые номера в таблице.. автоматически..

Последний раз редактировалось FReeMAN(Q); 18.04.2009 в 10:12.
FReeMAN(Q) вне форума Ответить с цитированием
Старый 18.04.2009, 10:28   #5
FReeMAN(Q)
Подтвердите свой е-майл
 
Регистрация: 13.04.2009
Сообщений: 8
По умолчанию

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
Скандербег, +1


и последнее, если таблица маленькая (или учебная задача) и со всем вышеуказанным заморачиваться не хочется, тогда, всё же лучше вместо количества записей брать максимальное значение счётчика:
Код:
  ADOQuery1.Close;
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select MAX(Код) as MaxCode from Tablica1');
  ADOQuery1.Open;
  if  ADOQuery1.IsEmpty then NextCode := 1
  else NextCode := ADOQuery1.FieldByName('MaxCode').AsInteger + 1;
  ADOQuery1.Close;
{всё можно добавлять новую запись с кодом NextCode}
попробовал ваш вариант кода он вносит новые записи с полем 1... 1... 1... 1... каждый раз...
FReeMAN(Q) вне форума Ответить с цитированием
Старый 18.04.2009, 10:34   #6
Скандербег
Форумчанин
 
Регистрация: 04.04.2009
Сообщений: 438
По умолчанию

Присвоение значения переменной есть (cntrec:=form1.Query2.fieldbyname(' pnom').AsInteger; ), а где тот самый запрос о количестве записей?
Вначале надо сделать запрос, а потом уже вытаскивать и присваивать кол-во записей.
Код:
  form1.Query2.Close; //если form1.Query2 закрыт (не активен) , то этот оператор вставлять не надо
  form1.Query2.SQL.text := 'select count(*) from pokupka';
  form1.Query2.Open;
  if not form1.Query2.Eof then
    cntrec:=form1.Query2.fieldbyname('COUNT').AsInteger + 1;
  form1.Query2.Close;
Цитата:
P.S.: и все же как при удаленнии одной записи присваивать остальным их порядковые номера в таблице.. автоматически..
А этого, практически, сделать и невозможно. Поэтому в базах применяют так называемый уникальный идентификатор (в нашем с вами понимании - номер записи). Особенность его в том, что при удалении записи этот номер больше никогда не используется. В этом случае, да, все делается автоматом, правда, реализация такого "автомата" зависит от типа базы. Но все равно, чтобы "автомат" заработал надо сделать несколько телодвижений.
В некоторых применяется, как сказал Serge_Bliznykov, автоинкрементное поле (пункт 1. в его посте).

Последний раз редактировалось Скандербег; 18.04.2009 в 10:45.
Скандербег вне форума Ответить с цитированием
Старый 18.04.2009, 11:14   #7
FReeMAN(Q)
Подтвердите свой е-майл
 
Регистрация: 13.04.2009
Сообщений: 8
Вопрос

спасибо вам за помощь.. последний вопрос..
при использовании данного кода

Код:
form1.Query2.Close; //если form1.Query2 закрыт (не активен) , то этот оператор вставлять не надо
  form1.Query2.SQL.text := 'select count(*) from pokupka';
  form1.Query2.Open;
  if not form1.Query2.Eof then
    cntrec:=form1.Query2.fieldbyname('COUNT').AsInteger + 1;
  form1.Query2.Close;
выдается ошибка о том что поле Count или в моём случае Pnom не найдено... почему?
FReeMAN(Q) вне форума Ответить с цитированием
Старый 18.04.2009, 11:18   #8
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
Сообщение от FReeMAN(Q)
попробовал ваш вариант кода он вносит новые записи с полем 1... 1... 1... 1... каждый раз...
не верю!
Надеюсь, что Вы догадались изменить выборку на:
Код:
  ADOQuery1.SQL.Add('select MAX(Pnom) as MaxCode from pokupka');
Приводите кусок программы целиком!!

Цитата:
Сообщение от FReeMAN(Q)
P.S.: и все же как при удаленнии одной записи присваивать остальным их порядковые номера в таблице.. автоматически..
Извините. Но это просто глупость! Почитайте для начала основы реляционных БД!
сделать,конечно, можно что угодно - и зайца можно научить курить, вот только ЗАЧЕМ?!! Нумеруйте записи при выборке, или в отчёте. зачем их в таблице номеровать то?!?!

p.s. Ага. Кажется понял. Ваша проблема в том, что Вы пытаетесь использовать естественный ключ в качестве искуственного. Подробнее можно об этом почитать здесь — Анатолий Тенцер, Естественные ключи против искуственных ключей
на подобные грабли мы неоднократно наступали.. ;(
у Вас поле pnom чтото означает для характеристики покупки?!? номер счёта или какой-то ещё номер, который нужен пользователю?!
Тогда, мой Вам совет:
(если структура таблицы (и программа) доступны Вам для модицикации, конечно!) добавляйте новое поле — настоящий уникальный идентификатор.
И делайте с полем pnom что душеньке угодно!
Serge_Bliznykov вне форума Ответить с цитированием
Старый 18.04.2009, 11:23   #9
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
выдается ошибка о том что поле Count или в моём случае Pnom не найдено... почему?
перепишите код так:
Код:
 form1.Query2.SQL.text := 'select count(*) as RCOUNT from pokupka';
  form1.Query2.Open;
  cntrec:=1;
  if not form1.Query2.IsEmpty then
    cntrec:=form1.Query2.fieldbyname('RCOUNT').AsInteger + 1;
  form1.Query2.Close;
p.s. и обязательно внимательно прочитайте мой предыдущий пост!
Serge_Bliznykov вне форума Ответить с цитированием
Старый 18.04.2009, 11:32   #10
Скандербег
Форумчанин
 
Регистрация: 04.04.2009
Сообщений: 438
По умолчанию

Цитата:
Сообщение от FReeMAN(Q) Посмотреть сообщение
выдается ошибка о том что поле Count или в моём случае Pnom не найдено... почему?
Можно так:
Код:
  cntrec := form1.Query2.fields[0].AsInteger + 1;
Скандербег вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как присвоить ячейке имя? Maxx Microsoft Office Excel 2 01.11.2008 11:30
НОМЕР ЗАПИСИ))) chekanoff БД в Delphi 2 02.04.2008 09:18
присвоить переменной целого типа значение поля key полученное в результате выполнения SQL запроса Worms БД в Delphi 5 10.01.2008 21:07
Как присвоить апостраф? Apollo_13 Общие вопросы Delphi 3 08.08.2007 14:37
Как выбрать при помощи SQL записи из набора данных pris БД в Delphi 4 22.05.2007 11:24