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

Вниз

каскадное копирование TSQL   Найти похожие ветки 

 
pleasure ©   (2010-02-18 13:28) [0]

существует три взаимосвязанных таблицы a->b->c ("c" подчинена "b", а "b" подчинена "а") меж ними связь один ко многим. каскадное удаление происходит на ура. а вот каким образом реализовать каскадное копирование ?
к примеру в таблице "а" копируем одну из строчек. следом копировать все свзяанные строки из "b" в неё же но с новым a.id, далее свзяанные строки из "с" ....
Проще говоря делается справочник прейскуранта услуг. а - прейскурант, b - услуги, с - составляющие услуг.
копирование предназначено для того, чтобы не вносить новые услуги и их составляющие с нуля.
к тому же у составляющих услуг должна быть ссылка адекватная новому Id услуги.
у кого какие соображения по этому поводу?


 
Sergey13 ©   (2010-02-18 13:34) [1]

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


 
Ega23 ©   (2010-02-18 13:37) [2]

Хранимка.


 
pleasure ©   (2010-02-18 13:41) [3]

возможно решение через тригер на данные таблицы inserted


 
pleasure ©   (2010-02-18 13:45) [4]

у меня выглядит
  INSERT into Preiskur ([name], [data], deistv, idDogov)
  values (@name,CAST(@data as smalldatetime),"1",@idDogov)
  select @idd =@@IDENTITY
 -- копирование в Справочник услуг услуг со старого прейскуранта
  insert into SUslugi ([name], idPreisk, idSOtd, kod, cena, tarifOMS,
  vnerealiz, TimeUsl, PrRacx, KocPacx, KocPacxPr, ItogPacx, Rentab,
  RentabPr,  ZPL,  idparent,  Amortiz, oldID)
 select [name],@idd, idSOtd,  kod,  cena,  tarifOMS,  vnerealiz, TimeUsl,
  PrRacx,  KocPacx,  KocPacxPr,  ItogPacx,  Rentab,  RentabPr,
  ZPL, "0", Amortiz, id
 from SUslugi WHERE SUslugi.idPreisk=@id

но это начало копируются старые услуги в новый прейскурант, а составляющие нет ;(, да и не должны. а вот отследить свзяанн.... короче не осиляю я такой длинной связки пока через запросы ((((((


 
pleasure ©   (2010-02-18 13:55) [5]

точно, надо на тригеры вставки повесить обработчики, пущай они и думают, а не мне голову ломать ;))))


 
Sergey13 ©   (2010-02-18 13:59) [6]

> [5] pleasure ©   (18.02.10 13:55)
> пущай они и думают, а не мне голову ломать ;))))

Хороший подход. Плодотворный.


 
12 ©   (2010-02-18 14:01) [7]


> Хранимка.

+1


> точно, надо на тригеры вставки повесить обработчики,

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


 
Sergey13 ©   (2010-02-18 14:06) [8]

Тригер тут вообще не к месту упомянут, ИМХО.


 
pleasure ©   (2010-02-18 14:07) [9]

Sergey13, а ваше предложение?


 
pleasure ©   (2010-02-18 14:13) [10]

не тригры точно здесь не помогут при а и b ещё прокатит а вот дальше начинается полнейший бардак. поторопился я (((


 
Sergey13 ©   (2010-02-18 14:18) [11]

> [9] pleasure ©   (18.02.10 14:07)

Я их написал в первом ответе.


 
Ega23 ©   (2010-02-18 14:26) [12]

DDL на таблицы давай.


 
pleasure ©   (2010-02-18 14:31) [13]

CREATE TABLE [dbo].[SPreiskur] (
 [id] int IDENTITY(1, 1) NOT NULL,
 [name] varchar(100) COLLATE Cyrillic_General_CI_AS NULL,
 [data] smalldatetime DEFAULT getdate() NOT NULL,
 [deistv] smallint DEFAULT 0 NOT NULL,
 [idDogov] int NULL,
 PRIMARY KEY CLUSTERED ([id]),
 CONSTRAINT [SPreiskur_fk] FOREIGN KEY ([idDogov])
 REFERENCES [dbo].[SDogovor] ([id])
 ON UPDATE CASCADE
 ON DELETE CASCADE
)
ON [PRIMARY]
GO

CREATE TABLE [dbo].[SUslugi] (
 [id] int IDENTITY(1, 1) NOT NULL,
 [name] varchar(250) COLLATE Cyrillic_General_CI_AS DEFAULT "-" NULL,
 [kod] char(15) COLLATE Cyrillic_General_CI_AS DEFAULT "99999" NULL,
 [cena] money DEFAULT 0 NOT NULL,
 [tarifOMS] money DEFAULT 0 NOT NULL,
 [vnerealiz] money DEFAULT 0 NOT NULL,
 [TimeUsl] float DEFAULT 0 NOT NULL,
 [PrRacx] money DEFAULT 0 NOT NULL,
 [KocPacx] money DEFAULT 0 NOT NULL,
 [KocPacxPr] float DEFAULT 0 NOT NULL,
 [ItogPacx] money DEFAULT 0 NOT NULL,
 [Rentab] money DEFAULT 0 NOT NULL,
 [RentabPr] float DEFAULT 0 NOT NULL,
 [ZPL] money DEFAULT 0 NOT NULL,
 [Amortiz] money DEFAULT 0 NOT NULL,
 [idSOtd] int NULL,
 [idParent] int DEFAULT 99999 NULL,
 [idPreisk] int NULL,
 [USERNAME] varchar(75) COLLATE Cyrillic_General_CI_AS DEFAULT user_name() NOT NULL,
 [MiagInv] money DEFAULT 0 NOT NULL,
 [MInvTime] float DEFAULT 0 NOT NULL,
 [prPervichn] bit DEFAULT 0 NOT NULL,
 PRIMARY KEY CLUSTERED ([id]),
 CONSTRAINT [SUslugi_fk] FOREIGN KEY ([idPreisk])
 REFERENCES [dbo].[SPreiskur] ([id])
 ON UPDATE CASCADE
 ON DELETE CASCADE,
 CONSTRAINT [SUslugi_fk2] FOREIGN KEY ([idSOtd])
 REFERENCES [dbo].[SOtdelen] ([id])
 ON UPDATE CASCADE
 ON DELETE CASCADE
)
ON [PRIMARY]
GO

CREATE TABLE [dbo].[EMedik] (
 [id] int IDENTITY(1, 1) NOT NULL,
 [idMedik] int NULL,
 [idUslugi] int NULL,
 [pacxod] float DEFAULT 0 NOT NULL,
 [stoim] money DEFAULT 0 NOT NULL,
 PRIMARY KEY CLUSTERED ([id]),
 CONSTRAINT [EMedik_fk] FOREIGN KEY ([idUslugi])
 REFERENCES [dbo].[SUslugi] ([id])
 ON UPDATE CASCADE
 ON DELETE CASCADE,
 CONSTRAINT [EMedik_fk2] FOREIGN KEY ([idMedik])
 REFERENCES [dbo].[SMedik] ([id])
 ON UPDATE CASCADE
 ON DELETE CASCADE
)
ON [PRIMARY]
GO


 
Ega23 ©   (2010-02-18 15:05) [14]

А дальше?
Что со всем этим нужно делать-то? Где бизнес-логика?


 
pleasure ©   (2010-02-18 15:15) [15]

а - прейскурант, b - услуги, с - составляющие услуг.
Старый прейскурант включает услуги, а услуги в свою очередь подразделяются на составляющие (медикаменты, работа и т.д.).
Нужно завести новый прейскурант. Чтобы не заносить все услуги и составляющие услуг делаем их копию из старого прейскуранта.

через for и while понятно как, а вот через запросы в ХП несовсем понятно как это реализовать. Точнее до половины "pleasure ©   (18.02.10 13:45) [4]" а дальше хз


 
Ega23 ©   (2010-02-18 15:25) [16]

Вечером напишу.


 
pleasure ©   (2010-02-18 16:09) [17]

а мне видно пора опять книжку перечитать по TSQL, но уже внимательнее (((


 
pleasure ©   (2010-02-19 09:14) [18]


> Ega23 ©   (18.02.10 15:25) [16]
>
> Вечером напишу.


;((


 
12 ©   (2010-02-19 09:54) [19]


> ;((

там делов то - сам бы написал давно

и я бы написал тебе, просто в sql синиаксис долгий, на каждый вздох - оператор, просто в лом писать :)


 
pleasure ©   (2010-02-19 10:09) [20]

каркас может не сложно накидать?


 
Ega23 ©   (2010-02-19 11:34) [21]

Щас накидаю.


 
b z   (2010-02-19 11:45) [22]

Например два select into должны справиться.


 
Ega23 ©   (2010-02-19 12:12) [23]


Create Table FirstTable (
FID int identity (1,1),
FName varchar(32) not null,
constraint PK_FirstTable primary key (FID)
);

Create Table SecondTable (
SID int identity (1,1),
FID int not null,
SName varchar(32) not null,
constraint PK_SecondTable primary key (SID)
);

Create Table ThirdTable (
TID int identity (1,1),
SID int not null,
TName varchar(32) not null,
constraint PK_TirdTable primary key (TID)
);

alter table SecondTable
  add constraint FK_Second_Ref_First foreign key (FID)
       references FirstTable (FID);

alter table ThirdTable
  add constraint FK_Third_Ref_Second foreign key (SID)
       references SecondTable (SID);

Set NoCount ON;

Insert into FirstTable (FName) Values ("First_1");
Insert into FirstTable (FName) Values ("First_2");

Insert into SecondTable (FID, SName) Values (1, "Second_1_1");
Insert into SecondTable (FID, SName) Values (1, "Second_1_2");
Insert into SecondTable (FID, SName) Values (2, "Second_2_1");
Insert into SecondTable (FID, SName) Values (2, "Second_2_2");

Insert into ThirdTable (SID, TName) Values (1, "Third_1_1_1");
Insert into ThirdTable (SID, TName) Values (1, "Third_1_1_2");
Insert into ThirdTable (SID, TName) Values (2, "Third_1_2_1");
Insert into ThirdTable (SID, TName) Values (2, "Third_1_2_2");
Insert into ThirdTable (SID, TName) Values (3, "Third_1_3_1");
Insert into ThirdTable (SID, TName) Values (3, "Third_1_3_2");
Insert into ThirdTable (SID, TName) Values (4, "Third_1_4_1");
Insert into ThirdTable (SID, TName) Values (4, "Third_1_4_2");



 
Ega23 ©   (2010-02-19 12:12) [24]


if exists (select * from sysobjects where id = object_id(N"[S_MyProc]") and OBJECTPROPERTY(id, N"IsProcedure") = 1)
drop procedure [S_MyProc]
GO
CREATE PROCEDURE S_MyProc

@ActNam varchar(32)="NONE",
@ID int = -1,
@parID int = -1,
@Name varchar(32) = ""

As
declare
 @aName varchar (32),
 @aID int,
 @x int;

if (@ID = -1) Goto FIN;

Set NoCount ON;

Set @ActNam = Upper(LTrim(RTrim(@ActNam)));
Set @aName = NULL;

if @ActNam = "FIRST.ADD"
begin
Select @aName = FName
 from FirstTable
 where FID = @ID;
if @aName is null Goto FIN; -- Нет записей c таким ID

Insert into FirstTable (FName) Values (@aName);
Select @aID = Scope_Identity();

Declare Cur cursor local static for
 Select SID, SName from SecondTable
  where FID = @ID;
Open Cur;

While (0=0)
begin
 Fetch Next from Cur into @x, @aName;
 if @@FETCH_STATUS <> 0 Break;
 exec S_MyProc @ActNam = "SECOND.ADD", @ID = @x, @parID = @aID, @Name = @aName;
end;

Close Cur;
Deallocate Cur;

Goto FIN;  
end;

if @ActNam = "SECOND.ADD"
begin

Select @aName = SName
 from SecondTable
 where SID = @ID;
if @aName is null Goto FIN; -- Нет записей c таким ID
Insert into SecondTable (FID, SName) Values (@parID, @aName);
Select @aID = Scope_Identity();

Insert into ThirdTable (SID, TName)
 Select SID=@aID, TName
  from ThirdTable
  where SID = @ID;

Goto FIN;
end;

FIN:
return(0);
GO



 
Ega23 ©   (2010-02-19 12:13) [25]

Использование:

exec S_MyProc @actNam=  "FIRST.ADD", @ID=1

Select * from FirstTable
Select * from SecondTable
Select * from ThirdTable


 
pleasure ©   (2010-02-19 12:39) [26]

o_O. Не может быть но работает корректно )), алгоритм ещё стоит разобрать и понять. Ega23 должен буду ;).  С наступающим Вас.


 
Ega23 ©   (2010-02-19 12:43) [27]


> алгоритм ещё стоит разобрать и понять


Обрати внимание на Scope_Identity(), в отличие от @@Identity.
Это тонкий момент, по нему посмотри в BOL.


 
pleasure ©   (2010-02-19 12:53) [28]

у меня MSSQL2000


 
Ega23 ©   (2010-02-19 12:55) [29]


> у меня MSSQL2000


я в синтаксисе 2000 и написал всё, "примочек" из 2005 и выше не использовал (да и не нужны они тут)


 
pleasure ©   (2010-02-19 12:58) [30]

Функции SCOPE_IDENTITY и @@IDENTITY возвращают последние значения идентификатора, созданные в таблицах во время текущего сеанса. Однако функция SCOPE_IDENTITY возвращает значения, вставленные только в рамках текущей области, тогда как действие функции @@IDENTITY не ограничивается никакими областями.


 
Ega23 ©   (2010-02-19 13:02) [31]

Угу. Т.е. у тебя таблица1 с identity и таблица2 c identity. И на первой таблице триггер висит на Insert. и в этом триггере идёт вставка чего-то во вторую.
Так вот, в этом случае Scope_Identity и @@Identity с большой вероятностью не совпадут, т.к. первая вернёт именно значение, вставленное в первую таблицу, а @@Identity - значение вставленной записи во вторую.


 
12 ©   (2010-02-19 13:02) [32]

короче, если во время вставки, триггер вдруг сработает какой - @@IDENTITY могет быть не той, которую ожидаешь

а не секрет если, что за контора? Имхо, в Саранске мало кому надо именно _писать_

Сам отсюда %)


 
Ega23 ©   (2010-02-19 13:02) [33]

Просто у тебя в скрипте как раз @@Identity использовалось, глаза резануло.


 
b z   (2010-02-19 13:21) [34]

declare @i int
insert into dbo.FirstTable (fname) values("123")
select @i = scope_identity()

insert into dbo.SecondTable
select @i as fid, st.sname as sname
from dbo.SecondTable as st
join dbo.FirstTable as ft on ft.fid=st.fid
where ft.fid=1

insert into dbo.ThirdTable
select
(select st2.sid from dbo.SecondTable as st2
 where st2.fid=@i and st.sname=st2.sname) as sid,
tt.tname as tname
from dbo.ThirdTable as tt
join dbo.SecondTable as st on st.sid=tt.sid
join dbo.FirstTable as ft on ft.fid=st.fid
where ft.fid=1


вроде так проще и понятнее. :)


 
Ega23 ©   (2010-02-19 13:48) [35]


> вроде так проще и понятнее. :)


Нет проверки, если в FirstTable нет записей с FID=1


 
Ega23 ©   (2010-02-19 13:51) [36]

Ну и потом, я специально такую мудрёную структуру наваял. Тут и пример с курсором, и проверка на отсутствие записей, и рекурсивный вызов ХП, и конструкция Insert into  Select from
А дальше автор пусть как хочет так и делает.


 
pleasure ©   (2010-02-19 13:53) [37]


> 12 ©  

В соседнем городе побратиме ;)) - Рузаевке


 
b z   (2010-02-19 14:04) [38]


> Нет проверки, если в FirstTable нет записей с FID=1
Тут же будет параметр его не с потолка берут, а если запись успели удалить (долго принимали решение, на клонирование) - на откуп пользователям. ;) Можно добавить и проверку +
> А дальше автор пусть как хочет так и делает.
.

Я к курсорам/рекурсиям прибегаю когда уж совсем без них никак.



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

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

Наверх




Память: 0.57 MB
Время: 0.048 c
15-1270812348
dars73
2010-04-09 15:25
2010.08.27
Как настроить локализацию


2-1268605992
Дмитрий
2010-03-15 01:33
2010.08.27
отправка пакета ( TcpClient )


4-1237892274
Alx2k
2009-03-24 13:57
2010.08.27
Получить оверлейный значок


2-1272953338
Беликов А.А
2010-05-04 10:08
2010.08.27
Конвертация TBitmap в TGPBitmap


15-1272275926
TUser
2010-04-26 13:58
2010.08.27
Как создать Кремниевую долину?