Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.02;
Скачать: CL | DM;

Вниз

Как поступить правильно, соблюдая каноны программирования?   Найти похожие ветки 

 
kyn66 ©   (2005-08-19 11:12) [0]

Уважаемые мастера, САБЖ. Есть таблица Таб1, в которой (после фильтра, к примеру) имеется 30 записей.
Каждая запись ессно имеет свой ID. У нее в подмастерьях имеется ешшо одна таблица Таб2, которая по ID
связана с Таб1. Мне нужно удалить все записи из Таб1 и ессно все подчиненные записи Таб2. Есть два варианта
удаления:
1) Я в цикле прохожу по всем записям Таб1 и через SQL-запрос удаляю все записи из Таб2, где есть связь по ID Таб1

while not Таб1.EOF do
  begin
       SQL.Add(Format("DELETE FROM %s WHERE OperID = :p1", [Tab2]));
       Parameters[0].Value := Таб1.FieldByName("ID").Value;
       ExecSQL;
       SQL.Clear;
       Таб1.Next;
  end;


2) Я опять-же в цикле прохожу по Таб1, в некую переменную (S : TStrings) собираю все ID таблицы Таб1, затем SQL-запрос
   выполняю тока 1 раз

       SQL.Add(Format("DELETE FROM %s WHERE OperID IN (S)", [Tab2]));
       ExecSQL;


И тот и другой способ отработают, но меня интересует как правильно нужно поступать?


 
Ega23 ©   (2005-08-19 11:29) [1]

Если ВСЕ записи, то
delete from Tab2
delete from Tab1

?


 
Ega23 ©   (2005-08-19 11:30) [2]

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


 
kyn66 ©   (2005-08-19 11:31) [3]

Ну, до этого я ешшо не дошел 8-(


 
Гаврила ©   (2005-08-19 11:39) [4]

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


 
Ega23 ©   (2005-08-19 11:55) [5]

Вот тебе пример ХП для MS SQL, с каскадным удалением:

Print  "S_RTTIProc - процедура для работы с RTTI системы"
go
if exists (select * from sysobjects where id = object_id(N"[S_RTTIProc]") and OBJECTPROPERTY(id, N"IsProcedure") = 1)
drop procedure [S_RTTIProc]
GO
CREATE PROCEDURE S_RTTIProc

@ActNam varchar(32)="NONE",
 .........
-- Остальные параметры
 .........

As
declare  
 @NULLGUID uniqueidentifier,
 @result int,
 @x int,
 @aSQL varchar(8000),
 @ss varchar(8000),
 @ss1 varchar(8000);

Set @NULLGUID = "00000000-0000-0000-0000-000000000000";
Set NoCount ON;
Set @Result=0;
Select @ActNam=RTrim(LTrim(UPPER(@ActNam)));

if @ActNam="CLASSFIELDS.DEL"
begin
Delete ClassFields where (@UNID=-1 or UNID=@UNID) and
             (@CLSID=-1 or CLSID=@CLSID) and
             (@FldTypCod=-1 or FldTypCod=@FldTypCod);
Select @Result=@UNID;
Goto Fin;
end;

if @ActNam="CLASSMETHODS.DEL"
begin
Delete ClassMethods
 where (@CLSMetCod=-1 or CLSMetCod=@CLSMetCod) and
    (@CLSID=-1 or CLSID=@CLSID);
Select @Result=@CLSMetCod;
Goto Fin;
end;

if @ActNam="CLASSSTATES.DEL"
begin
Delete ClassStates
 where (@UNID=-1 or UNID=@UNID) and
    (@CLSID=-1 or CLSID=@CLSID);
Select @Result=@CLSMetCod;
Goto Fin;
end;

if @ActNam="CLASSES.DEL"
begin
-- Сначала удалим ClassFields

exec S_RTTIProc @ActNam="ClassFields.Del", @CLSID=@CLSID;

-- Теперь удалим ClassMethods

exec S_RTTIProc @ActNam="ClassMethods.DEL", @CLSID=@CLSID;

 -- Удаляем ClassStates
exec S_RTTIProc @ActNam="ClassStates.DEL", @CLSID=@CLSID;

Delete Classes where CLSID=@CLSID;
Select @Result=@CLSID;
Goto Fin;
end;

fin:
set nocount off;
return(@result);
GO



 
kyn66 ©   (2005-08-19 12:03) [6]

>> Ega23
Во, млин, спасибо, ща буду пробывать разбираться. Да, но это относится  если ты пишешь  клиент-сервер? А если я просто на сервере держу базы а работаю с ними в обычном режиме?


 
Ega23 ©   (2005-08-19 12:09) [7]

А какая разница?
Всё дело в уровне абстракции. Сервер - это сервер. Клиент - это клиент. Могут оба физически находиться на одной машине. Могут - на разных. Механизм подключения-то - общий.


 
alex_***   (2005-08-19 12:37) [8]

DELETE T2 FROM T2 INNER JOIN T1 ON T2.OrderID = T1.ID AND {условие}

DELETE FROM T1 WHERE {условие}

хотя, если надо снести всё, то проще [1]


 
afanasic   (2005-08-19 12:44) [9]

Пример для Oracle

alter table Таб1 add constraint Имя_надстройки foregn key (id) references Таб2(id) on delete cascade;

Делаешь один раз и забываешь про эту проблему навсегда.
Что-то подобное должно быть и в других СУБД обязательно...


 
afanasic   (2005-08-19 12:45) [10]

Прошу прощения, Таб1 и Таб2 необходимо поменять местами!!!


 
Ega23 ©   (2005-08-19 12:46) [11]

Делаешь один раз и забываешь про эту проблему навсегда.

Угу. Удаляешь потом одну запись и теряешь пол-базы.
Не, автоматическое каскадное удаление - это зло. Хуже только сифилис.


 
afanasic   (2005-08-19 12:55) [12]

Для ликвидации ошибок программирования есть rollback и дамп...
А это правильный подход, сохраняющий целостность базы - записи во второстепенной таблице не имеют смысла без одной записи в главной, поэтому их просто необходимо удалить, чтобы не засо{заси}рать базу данных...


 
Ega23 ©   (2005-08-19 13:05) [13]

Если ты таким образом проектируешь базу, то пользователь потом, удалив одну запись из справочной таблицы, грохнет все рабочие.
Представь стандартную ситуацию: Тип товара -> Товар -> Заказ
Удалив товар какого-либо типа ты рискуешь потерять историю твоих заказов.
Исходя из этого, для пользователя НИКОГДА не ставлю каскадное удаление. Пусть лучше exception получит. А потом, если так надо, удалит заказы, удалит все товары этого типа и только потом удалит тип товара.
А приведённый выше пример хп - этио не пользовательская хп, а системная. Пользователь до неё достучаться НИКОГДА не сможет. Только разработчик. А он уже знает, что такое удаление одного класса (для той хп).


 
Гаврила ©   (2005-08-19 13:08) [14]


>  [13] Ega23 ©  


> НИКОГДА не ставлю каскадное удаление


зависит от задачи, не так ли?


 
Ega23 ©   (2005-08-19 13:12) [15]

2 Гаврила ©   (19.08.05 13:08) [14]
зависит от задачи, не так ли?

обрати внимание на для пользователя НИКОГДА не ставлю

Конечно зависит от задачи.
Но преимущество использования хп для этого ещё в том, что, например, после удаления ты можешь занести запись в лог (не transaction log, а свой). Можешь ещё сделать массу полезных вещей. Наложение же on delete cascade на constraint такой возможности не даёт.
Поэтому и считаю этот механизм вредным и развращающим разработчика.


 
Desdechado ©   (2005-08-19 13:27) [16]

2 Ega23
ну, на справочники я, например, on delete cascade не ставлю и не даю из них удалять, если есть зависимые записи
но на многие другие вещи это очень удобно
например, объект - в одной таблице, а его свойства - по другим таблицам раскиданы
дропаю объект и не заморачиваюсь о свойствах


 
Leonid Troyanovsky ©   (2005-08-19 13:30) [17]


> afanasic   (19.08.05 12:55) [12]
> Для ликвидации ошибок программирования есть rollback и дамп...
>


Лучший метод ликвидации ошибок программирования -
ликвидация их носителей.

--
Regards, LVT.


 
Ega23 ©   (2005-08-19 13:48) [18]

например, объект - в одной таблице, а его свойства - по другим таблицам раскиданы
дропаю объект и не заморачиваюсь о свойствах


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


 
Val ©   (2005-08-19 13:50) [19]

>[9] afanasic   (19.08.05 12:44)
Вроде анси это.
>All
Спор о каскадном удалении - ограничения против хп считаю глупым абсолютно - категория "Что лучше - ложка или вилка?".


 
Sergey13 ©   (2005-08-19 13:51) [20]

Удалено модератором


 
Val ©   (2005-08-19 13:54) [21]

Удалено модератором


 
Ega23 ©   (2005-08-19 13:55) [22]

Удалено модератором


 
Sergey13 ©   (2005-08-19 13:56) [23]

Удалено модератором


 
Val ©   (2005-08-19 14:10) [24]

Удалено модератором


 
Sergey13 ©   (2005-08-19 14:14) [25]

Удалено модератором


 
Val ©   (2005-08-19 14:20) [26]

Удалено модератором


 
DiamondShark ©   (2005-08-19 14:27) [27]


> kyn66 ©   (19.08.05 11:12)  

А тип используемой СУБД нет желания огласить?


 
afanasic   (2005-08-19 14:35) [28]

Согласен, что on delete cascade нужно правильно использовать, то пример Ega23 © никак не подходит - зачем тебе знать историю заказов несуществующего товара??? Если ты хочешь "удалить" товар, то есть, чтобы его не видел пользователь, то достаточно завести поле типа Boolean и проставлять признак, а удаленные потом не показывать... В этом случае у тебя сохраняется структурность и логичность базы, а все эти ручные удаления рано или поздно могут где-нибудь всплыть...


 
kyn66 ©   (2005-08-19 14:48) [29]

>> alex_***   (19.08.05 12:37) [8]
А что-то я не понял этой строки?
DELETE T2 FROM T2 INNER JOIN T1 ON T2.OrderID = T1.ID AND {условие} Не очепятка случаем?


 
alex_***   (2005-08-19 15:39) [30]

а что не понятно? условие можешь выкинуть, если не нужно


 
alex_***   (2005-08-19 15:40) [31]

у тебя какой сервер, в самом деле?



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

Текущий архив: 2005.10.02;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.054 c
2-1124861042
nk
2005-08-24 09:24
2005.10.02
Работа с файлами...


2-1124965240
Laymer
2005-08-25 14:20
2005.10.02
Компоненты


14-1126526196
Mati
2005-09-12 15:56
2005.10.02
Многомерная оптимизация


6-1118145687
Flame
2005-06-07 16:01
2005.10.02
idhttp непоолный url


10-1105126065
darevil
2005-01-07 22:27
2005.10.02
Как подключиться к запущенным экземплярам Explorer a?