Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2002.01.14;
Скачать: [xml.tar.bz2];

Вниз

Вставка записей в 2 таблицы   Найти похожие ветки 

 
Shoo   (2001-12-13 13:20) [0]

Мастера, интересует такая вещь: имею БД на MS SQL 7.0, использую ADO, имеется 2 таблицы, KatNakl и SpNakl, связанные таким образом: SpNakl.cNakl -> KatNakl.NRec. По нажатию кнопки хочу добавить данные в обе таблицы, у TADOQuery использую свойство SQL для формирования запроса на добавление и метод ExecSQL для выполнения запроса, примерно так:

procedure TForm1.Button1Click(Sender: TObject);
var mycNakl: longint;
begin
mycNakl := 0;
ADOQuery1.SQL.Clear;
with ADOQuery1.SQL do
begin
Add("insert into katnakl (datenakl, smena, priznak)");
Add("values (""10.12.2001"", 1, ""1"")");
end;
ADOQuery1.ExecSQL;

//как здесь получить новое значение поля NRec в KatNakl,
//записав его, скажем в mycNakl,
//чтобы подставить его в cNakl таблицы SpNakl?

ADOQuery1.SQL.Clear;
with ADOQuery1.SQL do
begin
Add("insert into spnakl (cnakl, name)");
Add("values (" + IntToStr(mycNakl) + ", ""QQQQQQQ""");
end;
ADOQuery1.ExecSQL;
end;
end;

И вообще, правильным ли путем я иду? Как лучше вставлять данные в моем случае? Заранее благодарен.


 
neXt   (2001-12-13 13:31) [1]

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


 
Delirium   (2001-12-13 13:43) [2]

Существует специальная функция для генерации уникальных идентификаторов
NEWID тип uniqueidentifier, это значение каждый раз новое и абсолютно уникальное. На мой взгляд исользование таких идентификаторов - самый грамотный подход.


 
Shoo   (2001-12-13 14:06) [3]

2neXt:
Увы, для меня это все еще не так просто. Если несложно, на основе моего примера, приведите, плз, очень сжато, примерный текст хранимой процедуры, которая будет этим заниматься и как ее потом корректно вызывать? Спасибо.


 
Shoo   (2001-12-13 14:15) [4]

И еще, прошу извинить, я забыл написать, что поле KatNakl.NRec является первичным ключом, формируемым автоматически и именно его значение мне нужно получить для записи данных во вторую таблицу


 
neXt   (2001-12-13 14:17) [5]

Дай полный список полей обоих таблиц с типами


 
Shoo   (2001-12-13 14:29) [6]

2neXt:
Да, пожалуйста:

Table KatNakl:
Fields
NRec - numeric (primary key)
DateNakl - DateTime
Smena - int
Priznak - char

Table SpNakl:
Fields
NRec - numeric (primary key)
cNakl - numeric (связана с KatNakl.NRec)
BarCod - numeric
Name - char
Kol - numeric

Если есть необходимость, типы полей можно изменить, БД пока пуста.


 
neXt   (2001-12-13 14:51) [7]

технические подробности:
Ключ NRec в таблицах стоит как IDENTITY ? или его значение нужно наигрывать перед каждым добавлением


 
Shoo   (2001-12-13 14:59) [8]

Да, как IDENTITY.


 
neXt   (2001-12-13 15:05) [9]

-- Ну позно, я написал уже для простого поля, но поправить не сложно
-- не проверял так что это только пример
----------------------------------------------------------------
if object_id("KatNakl_SpNakl_Insert") is not null
drop proc KatNakl_SpNakl_Insert

GO
create proc KatNakl_SpNakl_Insert
@KatNakl_NRec numeric = null output, --Выходной параметр идентификатор KatNakl
@SpNakl_NRec numeric = null output, --Выходной параметр идентификатор SpNakl
-- Значения полей таблицы KatNakl
@DateNakl DateTime ,
@Smena int ,
@Priznak char ,
-- Значения полей таблицы SpNakl
@BarCod numeric ,
@Name char ,
@Kol numeric
as
declare @RetVal int

select @RetVal = 0 -- Если всё выполнилось удачно , то вернёт 0

-- Либо всё - либо ничего !!!
begin tran save tran TRAN_INSERT_KatNakl_SpNakl

-- Найдём новое не занятое значение первичного ключа
select @KatNakl_NRec = isnull( max(NRec) + 1 , 1 )
from KatNakl

-- Добавим запись в KatNakl
insert into KatNakl
(
NRec ,
DateNakl,
Smena ,
Priznak
)
select
@KatNakl_NRec,
@DateNakl ,
@Smena ,
@Priznak

-- Проверим добавилось ли?
if @@rowcount <> 1
begin
-- Код оибки добавления записи в
-- первую таблицу (можно выработать
-- свою систему нумерации ошибок)
@RetVal = 1000
-- Отменяем неудачное действие
rollback TRAN_INSERT_KatNakl_SpNakl
-- И на выход
goto EXIT_OFF
end

-- Найдём новое не занятое значение первичного ключа
select @SpNakl_NRec = isnull( max(NRec) + 1 , 1 )
from SpNakl

-- Если все хорошо то добавляем запись во вторую таблицу
insert into SpNakl
(
NRec ,
cNakl ,
BarCod ,
Name ,
Kol
)
select
@SpNakl_NRec ,
@KatNakl_NRec,
@BarCod ,
@Name ,
@Kol

if @@rowcount <> 1
begin
-- Код оибки
@RetVal = 1001
-- Отменяем неудачное действие
rollback TRAN_INSERT_KatNakl_SpNakl
-- И на выход
goto EXIT_OFF
end

EXIT_OFF:
commit tran
return @RetVal
GO


 
neXt   (2001-12-13 15:10) [10]

я по ADO не спец, могу сказать как из стандартной TQuery вызывать, уверен что один фиг


 
Shoo   (2001-12-13 15:14) [11]

2neXt:
Спасибо, постараюсь проверить в течение ближайшего времени...


 
Shoo   (2001-12-13 15:15) [12]

Да, кстати, как вызвать-то? А в ADO, действительно, все будет аналогично.


 
NewComer   (2001-12-13 15:21) [13]

вот я подумал.....
использование identity влечет за собой проблеммы подобного рода.
по-моему все ж лучше использовать в качестве идентификаторов GUID и получать их функцией NewID, будешь знать значение идентификатора перед вставкой. Тут NexT написал целую процедуру (и не лень было ? :-) ), я предлагаю в ней поставить уровень изоляции для транзакции SERIALIZABLE, чтобы небыло накладок при повторном селекте из первой таблицы.


 
Delirium   (2001-12-13 15:25) [14]

Согласен с NewComer, то, что предлагает neXt - в общем-то устаревший подход, а GUID - решает кучу проблем.


 
neXt   (2001-12-13 15:35) [15]

В Query.SQL пишем
------------------------------------------------
declare @KatNakl_NRec numeric,
@SpNakl_NRec numeric,
@RetVal int

exec @RetVal = KatNakl_SpNakl_Insert
@KatNakl_NRec = @KatNakl_NRec ,
@SpNakl_NRec = @SpNakl_NRec ,
@DateNakl = :DateNakl ,
@Smena = :Smena ,
@Priznak = :Priznak ,
@BarCod = :BarCod ,
@Name = :Name ,
@Kol = :Kol

select @KatNakl_NRec As KatNakl_NRec_NewID,
@SpNakl_NRec As SpNakl_NRec_NewID ,
@RetVal As ErrorCode
-----------------------------------------------
Нужно ещё добавить в Query.Fields три поля поля:
KatNakl_NRec_NewID
SpNakl_NRec_NewID
ErrorCode
,а в окошечке свойства Query.Params появятся все параметры указанные с двоеточием в первом символе (см Query.SQL)
а именно
:DateNakl
:Smena
:Priznak
:BarCod
:Name
:Kol
у каждого из них нужно выстовить (обязательно) свойство DataType
--------------------------------------------------------
это почти всё, НО
нужно ещё передать из кода Delphi значения параметров чтобы произошло добавление записей
это делается так
когда нужно добавить запись выполняется следующий код
///////////////
Query.Params[0].AsDataTime := (*DateNakl - значение*);
Query.Params[1].AsInteger := (*Smena - значение*);
Query.Params[2].AsString := (*Priznak - значение*);
Query.Params[3].AsFloat := (*BarCod - значение*);
Query.Params[4].AsString := (*Name- значение*);
Query.Params[5].AsFloat := (*Kol - значение*);
Query.Open;
/////////////////////
далее можно проверить добавилась ли запись взглянув в поле
Query.FieldByName("ErrorCode").AsInteger
если там 0 - всё окей если нет то надо думать
идентификаторы добавленных записей доступны соответственно из полей
Query.FieldByName("KatNakl_NRec_NewID").AsInteger
Query.FieldByName("SpNakl_NRec_NewID").AsInteger
если надо


 
neXt   (2001-12-13 15:36) [16]

устаревший , но работающий


 
neXt   (2001-12-13 15:41) [17]

кстати GUID многого не позволяет
например (это не относится к данному случаю) при использовании IDENTITY или его заменителя как в том решении что выше, есть возможность использовать "маленькие ID-шники" закрытые диапазоны идентифокаторов , например для дистрибутивных данных


 
neXt   (2001-12-13 15:47) [18]

кроме того GUID не поддерживается некоторыми SQL - платформами , для меня это существенное ограничение


 
Delirium   (2001-12-13 15:50) [19]

"закрытые диапазоны идентифокаторов" А часто-ли это надо? Если и надо, то лучше создать дополнительное поле с псевдоидентификатором, а опираться всё равно на GUID. Если для каждой пары (тройки) таблиц присать свою процедуру - вероятность ошибки вырастает! Кроме того - как быть с удалёнными серверами? - придётся создавать глобальные хранилища идентификаторов, создавать систему рассылки и т.п. А GUID-метод, не мене "работающий" но гораздо более удобный, да и индексация по uniqueidentifier в MSSQL оптимизирована.


 
Delirium   (2001-12-13 15:58) [20]

"GUID не поддерживается некоторыми SQL - платформами" - Shoo - же работает с MSSQL :)


 
neXt   (2001-12-13 16:11) [21]

GUID нельзя сравнивать , даже произносить в слух не рекомендуется
что касается индексирования полей uniqueidentifier то это тоже самое что и bigint преимуществ никаких (ещё бы они не индексировались они же для ID придуманы!)


 
NewComer   (2001-12-13 16:19) [22]

А при чем тут сравнение идентификаторов?
первичные ключи не должны обладать такой функциональностью.
Я конечно сомневаю в эффективности индексов по ним .. но все же.
Делать то кластерный индекс по ним тебя никто не заставляет.


 
Delirium   (2001-12-13 16:21) [23]

"GUID нельзя сравнивать" ты имеешь в виду сортировку?
А с какой стати сортировка должна сториться по идентификаторам?
Операции с идентификаторами "=" и "<>" больше и не надо, это вредно!


 
neXt   (2001-12-13 16:21) [24]

ЧЕСНО ГОВОРЯ У меня не 100 процентных аргументов против uniqueidentifier только вот работать с ним не привычно и не удобно


 
neXt   (2001-12-13 16:23) [25]

не ну последовательность заполнения таблицы


 
Delirium   (2001-12-13 16:25) [26]

"не привычно" - возможно, "не удобно" - предрассудки


 
neXt   (2001-12-13 16:26) [27]

и ещё если уж есть поля с каким-то типом то значит в процедурах будут применятся переменные с этимже типом, а как GUID"ом заменить выражение
exec Procedure_
@ID = @ID out
if @ID = 0
begin
--- то-то и то-то
end


 
neXt   (2001-12-13 16:27) [28]

причем null , допустим уже занят каким-то смыслом


 
Delirium   (2001-12-13 16:36) [29]

Хм, а в какой ситуации идентификатор вообще может содежать значения типа Null или просто 0 ? Это уже не идентификатор а просто поле с цифрами получается :)


 
NewComer   (2001-12-13 16:40) [30]

to NeXt:
не должен null быть занят каким то смыслом, null он и в Африке null.
Ну а если уж занят, то {00000000-0000-0000-0000-000000000000} вот тебе и обнуленный идентификатор.


 
Delirium   (2001-12-13 16:47) [31]

Совсем упустил из виду "последовательность заполнения таблицы" это нонсенс, по идентификаторам определять прорядок занесения информации!


 
neXt   (2001-12-13 16:53) [32]

значение null принемет не поле а переменная, например
select @ID = ID from ...
если там нет не одной пожходящей записи


 
neXt   (2001-12-13 16:56) [33]

чесно говоря, рассматривая выражения вида
select @ID = isnull(ID ,{00000000-0000-0000-0000-000000000000})
и
select @ID = isnull(ID ,0)
моё предпочтение остаётся со старым добрым numeric или int


 
NewComer   (2001-12-13 17:00) [34]

NeXt! сдавайся! :-)))))
очень много аргументов в Пользу Guid. И вообще.. каждый пишет так, как ему удобней. Но сдаеться мне, что корни identity растут с аксесса, с однопользовательской системы.


 
Delirium   (2001-12-13 17:01) [35]

На самом деле можно просто:

Declare @I uniqueidentifier
select @I=null


 
neXt   (2001-12-13 17:03) [36]


Совсем упустил из виду "последовательность заполнения таблицы" это нонсенс, по идентификаторам определять прорядок занесения информации!

речь не о сортировке или явного определения последовательности, а вот о чем
при работе со временными таблицами (или с разбитыми по @@spid)
1.прошёл инсерт
2.в max(ID) мой только что внесённый ID-шник
удобно, особенно если инсерт - это процедура откуда ID ещё надо тянуть



 
NewComer   (2001-12-13 17:05) [37]

select @ID = isnull(ID ,{00000000-0000-0000-0000-000000000000})
кстати сие выражени попахивает потенциальной ошибкой. ГЫ.


 
neXt   (2001-12-13 17:07) [38]

не не сдамся, я не вынужден писать не на одном MSSQL и выгрузка скажем в text или чего доброго в Sybase для полей GUID оборачивается серьёзным геморроем


 
NewComer   (2001-12-13 17:07) [39]

"1.прошёл инсерт
2.в max(ID) мой только что внесённый ID-шник
удобно, особенно если инсерт - это процедура откуда ID ещё надо тянуть"
Необходимо отучаться от "однопользователького" метода мышления. ГЫ


 
neXt   (2001-12-13 17:08) [40]

выше: "вынужден"


 
neXt   (2001-12-13 17:09) [41]

не ну чем тогда GUID лучше timestamp тоже не с чем не совместим и индексируется на зашибись


 
neXt   (2001-12-13 17:10) [42]

или тоже устаревший подход


 
Delirium   (2001-12-13 17:10) [43]

Это изначально "кривой" метод и естесвенно, прямо реализовать его с uniqueidentifier не получится, однако есть же триггера :)


 
Delirium   (2001-12-13 17:12) [44]

"чем тогда GUID лучше timestamp тоже не с чем не совместим и индексируется на зашибись" - вернёмся к удалённым серверам :)


 
NewComer   (2001-12-13 17:13) [45]

timestamp - вообще специфичная штука, и не имеет никакого отношения к uniqueidentifier, тем более этот тип нельзя использовать для ключей.


 
neXt   (2001-12-13 17:15) [46]

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


 
NewComer   (2001-12-13 17:15) [47]

Ой.. насчет timestamp я погарячился..... :-)


 
neXt   (2001-12-13 17:21) [48]

timestamp нормально подходит на роль ключа уж во всяком случае ни чем не хуже guid"а я не защищаю его, только как альтернатива, а сточки зрения разработчика эти типы вообще отличаются только алгоритмом генерации и размером


 
Delirium   (2001-12-13 17:26) [49]

В timestamp гарантированая уникальность только в составе одной машины!
И это лишает его права быть глобальным идентификатором. И вообще это всё уже давно флейм - жизнь нас рассудит :)


 
NewComer   (2001-12-13 17:27) [50]

Предлагаю закрыть этот вопрос.
Не... И все-таки я не понял почему ты высказал эту фразу "в борьбе за отказ от "однопользовательского" мышления , так же, предлягаю отказаться от транзакций, и прочих прежитков "тяжёлого прошлого" вроде блокировак, а ещё ролей , пользователей и технологии "клиент-сервер""




Страницы: 1 2 вся ветка

Форум: "Базы";
Текущий архив: 2002.01.14;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.73 MB
Время: 0.071 c
3-42337
victor
2001-12-10 07:47
2002.01.14
добавление записи с если первичный индекс автоинкрементный


3-42343
Alexsandr
2001-12-10 04:33
2002.01.14
вопрос


1-42471
dimonf
2001-12-24 17:15
2002.01.14
Как быстро выводить (прорисовывать) графическую информацию на Canvas?


1-42509
Sergo
2001-12-26 10:15
2002.01.14
Кто-нибудь может подсказать алгоритм поворота растрового изображения?


1-42440
Philya
2001-12-21 18:00
2002.01.14
кодировка





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский