2010-04-30 5 views
0

Я пытаюсь определить хороший способ обработки приведенного ниже сценария. Я имею следующие две таблицы базы данных вместе с образцами данных. Таблица 1 содержит распределения, сгруппированные по проекту. Проект может иметь один или несколько распределений. В дистрибутиве может быть одна учетная запись. У учетной записи есть процент, выделенный ей. Распределения могут быть изменены путем добавления или удаления учетной записи, а также изменения процентных ставок.SQL для вставки последней версии группы элементов

Таблица2 отслеживает распределение, присваивая номер версии каждому распределению. мне нужно, чтобы иметь возможность скопировать новые дистрибутивы из Table1 в Table2, но только при двух условиях:

1. the entire distribution does not already exist 
2. the distribution has been modified (accounts added/removed or percentages changed). 

Примечание: При копировании распределения из Table1 в Table2 Мне нужно сравнить все счета и проценты в пределах чтобы определить, существует ли она. При вставке нового дистрибутива мне нужно увеличить значение VersionID (max (VersionID) + 1).

Итак, в приведенном примере распределение (12345, 1) было изменено, добавив номер счета 7, а также изменив процентное распределение. Весь дистрибутив должен быть скопирован во вторую таблицу, увеличивая значение параметра VersionID до 3 в процессе.

базы данных в вопросе SQL Server 2005.

Table1 
------ 
ProjectID AccountDistributionID AccountID Percent 
12345  1      1   25.0 
12345  1      2   25.0 
12345  1      7   50.0 
56789  2      3   25.0 
56789  2      4   25.0 
56789  2      5   25.0 
56789  2      6   25.0 

Table2 
------ 
ID VersionID Project ID AccountDistributionID AccountID Percent 
1 1   12345  1      1   50.0 
2 1   12345  1      2   50.0 
3 2   56789  2      3   25.0 
4 2   56789  2      4   25.0 
5 2   56789  2      5   25.0 
6 2   56789  2      6   25.0 
 

ответ

0

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

Insert Table2(VersionId, ProjectId, AccountDistributionId, AccountId, Percent) 
Select Coalesce(
       (
       Select Max(VersionId) 
       From Table1 As T1 
       Where T1.Id = T.Id 
       ), 0) + 1 As VersionId 
    , ProjectId, AccountDistributionId, AccountId, Percent 
From Table1 As T 
Where ProjectId = 12345 
    And AccountDistributionId = 1 

Что касается определения «любого нового распределения», которое является более жестким, и это зависит от того, как определено «новое».

Сложение

Вы спрашивали о том, как определить, что множество изменилось. Одним из решений является сохранение хэша значений с распределением учетной записи при его сохранении. Так что-то вроде:

Update AccountDistributions 
Set AccountHash = HashBytes('SHA1' 
          , (
           Select '|' + Cast(AccountId As varchar(10)) + '|' + Cast(Percent As varchar(30)) 
           From Table1 As T1 
           Where T1.AccountDistributionID = AccountDistributions.Id 
           Order By T1.AccountId, T1.Percent 
           For Xml Path('') 
          )) 

Тогда вы можете использовать это, чтобы определить, был ли изменен какой-либо член набора. Другим решением было бы обновить значение DateTime в родительской таблице всякий раз, когда произошла смена этого набора, и записать одно и то же значение в таблицу2. Затем вы можете сравнить последнее значение DateTime с DateTime в родительской таблице, чтобы определить, изменилось ли что-либо.

+0

Hi Thomas! Спасибо за предложение. То, что я нахожу более жестким, определяет, когда нужно вставлять новую версию, потому что мне нужно сравнить то, что в настоящее время существует с тем, что вставляется, и только вставить весь набор, если он был изменен или он ранее не существовал. – Garett

0

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


declare @accountDistributionVersionID int 

select @accountDistributionVersionID = isnull(max(VersionID), 0) 
from Table2 

insert into Table2 
select @accountDistributionVersionID + rank, 
     ProjectID, AccountDistributionID, AccountID, Percent 
from 
(
    select D.*, 
      dense_rank() over (order by ProjectID, AccountDistributionID) as rank 
    from 
    (
     select distinct t2.* from 
     (
      select t.ProjectID, t.AccountDistributionID, t.AccountID, t.Percent 
      from Table1 as t 
      where not exists(select * from Table2 as t2 
          where t2.ProjectID = t.ProjectID 
          and t2.AccountDistributionID = t.AccountDistributionID 
          and t2.AccountID = t.AccountID 
          and t2.Percent = t.Percent 
          and VersionId = (select max(VersionID) 
              from compass.Table2 t3 
              where t2.ProjectID = t3.AccountDistributionID 
              and t2.AccountDistributionID = t3.AccountDistributionID)) 
     ) as t 
     cross apply 
     (
      select t3.ProjectID, t3.AccountDistributionID, t3.AccountID, t3.Percent 
      from Table1 As t3 
      where t.ProjectID = t3.ProjectID 
      and t.AccountDistributionID = t3.AccountDistributionID 
     ) as t2 
    ) as D 
) as T 

  • Я получаю максимальную VERSIONID из таблицы назначения.
  • Я извлекаю только те учетные записи, которые были изменены из исходной таблицы, генерируя номер версии psuedo, используя функцию DENSE_RANK.
  • Наконец я вставить в таблицу назначения, с VersionID из (ранее получен максимальный VERSIONID) + ранг

Это, кажется, работает хорошо. Отзыв был бы очень благодарен.

Смежные вопросы