Две таблицы с эффективными датами, в которых данные могут изменяться независимо - PullRequest
2 голосов
/ 24 сентября 2011

Я занимаюсь разработкой базы данных в MS Access 2010. У меня есть две таблицы: одна для сделок (tblDeals), а другая для позиций сделок (tblDealItems).

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

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

Таблицы содержат следующие данные для одной конкретной сделки "Сделка 3":

tblDeals:
DealID DealName AssetClassID DateEffective DateEnd
------ -------- ------------ ------------- -------
3      Deal 3   3            1 Jan 2010    1 Jul 2011
3      Deal 3   2            1 Jul 2011    1 Oct 2011
3      Deal 3   1            1 Oct 2011 

tblDealItems:
DealItemID DealID CategoryID ParticipantID Amount DateEffective DateEnd
---------- ------ ---------- ------------- ------ ------------- -------
13         3      3          2             1500   1 Jan 2010    1 Jun 2011
13         3      1          2             1500   1 Jun 2011    6 Jun 2011
13         3      1          2             6000   6 Jun 2011    1 Sep 2011
13         3      3          2             6000   1 Sep 2011 

Таким образом, реальная история сделки - это то (что я хотел бы вернуть) (созданное вручную - это (за исключением столбца «Описание» - которое там есть, поэтому очевидно, что изменилось в каждой строке)) :

Date       (Description)         DealID DealName AssetClassID CategoryID ParticipantID Amount
---------- --------------------- ------ -------- ------------ ---------- ------------- ------
1 Jan 2010 (Deal 3 Created)      3      Deal 3   3            3          2             1500
1 Jun 2011 (Category Changed)    3      Deal 3   3            1          2             1500
6 Jun 2011 (Amount Changed)      3      Deal 3   3            1          2             6000
1 Jul 2011 (Asset Class Changed) 3      Deal 3   2            1          2             6000
1 Sep 2011 (Category Changed)    3      Deal 3   2            3          2             6000
1 Oct 2011 (Asset Class Changed) 3      Deal 3   1            3          2             6000

Очевидно, что если я соединю две таблицы по их общему ключу, я получу таблицу с двенадцатью строками (3 * 4) вместо шести строк, которые описывают историю.

Я знаю, что мне нужно каким-то образом объединить столы, чтобы я мог создать реальную историю сделки, но я просто не знаю, как! (Я действительно парень из Excel, а не из SQL!)

Я думаю, что я разработал именно то, что требуется для решения указанной выше проблемы:

Для каждой даты в qryDates мне нужно найти самое большое значение tblDeals.DateEffective, которое меньше или равно этой дате, и самое большое значение tblDealItems.DateEffective, которое меньше или равно этой дате.

Мне нужно вернуть строку из запроса, соединяющего tblDeals и tblDealItems, которая имеет эти две точные даты.

С благодарностью получена любая помощь.

1 Ответ

2 голосов
/ 26 сентября 2011

Я опускаю «Описание» на данный момент, потому что это добавляет немного сложности (и может быть лучше подходит для отчета в любом случае):

Первый

 CREATE VIEW qryDates 
 AS
  SELECT DISTINCT T1.DealID, 
         T1.DateEffective AS tblDeals_DateEffective, 
         (
          SELECT MAX(T2.DateEffective)
            FROM tblDealItems AS T2
           WHERE T1.DealID = T2.DealID
                 AND T2.DateEffective <= T1.DateEffective
         ) AS tblDealItems_DateEffective
    FROM tblDeals AS T1;

Второе:

 CREATE VIEW qryDates2
 AS
  SELECT DISTINCT T2.DealID, 
         T2.DateEffective AS tblDealItems_DateEffective, 
         (
          SELECT MAX(T1.DateEffective)
            FROM tblDeals AS T1
           WHERE T1.DealID = T2.DealID
                 AND T1.DateEffective <= T2.DateEffective
         ) AS tblDeals_DateEffective
    FROM tblDealItems AS T2

Тогда

SELECT T2.DateEffective AS [Date], '' AS Description, 
       T1.DealName, T1.AssetClassID, 
       T2.CategoryID, T2.ParticipantID, T2.Amount
  FROM (
       tblDeals AS T1
       INNER JOIN 
       qryDates2 AS Q2
          ON T1.DateEffective = Q2.tblDeals_DateEffective
             AND T1.DealID = Q2.DealID
       )
       INNER JOIN tblDealItems AS T2
          ON T2.DateEffective = Q2.tblDealItems_DateEffective
             AND T2.DealID = Q2.DealID
UNION 
SELECT T1.DateEffective AS [Date], '' AS Description, 
       T1.DealName, T1.AssetClassID, 
       T2.CategoryID, T2.ParticipantID, T2.Amount
  FROM (
       tblDeals AS T1
       INNER JOIN 
       qryDates AS Q1 
          ON T1.DateEffective = Q1.tblDeals_DateEffective
             AND T1.DealID = Q1.DealID
       )
       INNER JOIN tblDealItems AS T2
          ON T2.DateEffective = Q1.tblDealItems_DateEffective
             AND T2.DealID = Q1.DealID;

Качество данных в вашей выборке хорошее: в действительности объединения могут быть внешними, чтобы компенсировать неверные данные. Обратите внимание, что ваша таблица tblDeals не полностью нормирована (подсказка: DealName повторяется).

Примечание:

Очевидно, что если я соединю две таблицы на их общем ключе, я получу таблицу с двенадцатью рядами (3 * 4) вместо шести рядов, которые описывают история.

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

SELECT DealID, DateEffective
  FROM tblDeals
UNION 
SELECT DealID, DateEffective
  FROM tblDealItems;

Вот репродукция: создает новую mdb во временной папке, создает таблицы и представления (примечание CREATE VIEW работает в Access;), добавляет тестовые данные (в соответствии с вопросом), затем выполняет запрос и показывает результаты в окне сообщения; ссылки не требуются, просто скопируйте + вставьте в любой модуль VBA, например. использовать новую книгу Excel:)

Sub NickNick2()

  On Error Resume Next
  Kill Environ$("temp") & "\DropMe.mdb"
  On Error GoTo 0

  Dim cat
  Set cat = CreateObject("ADOX.Catalog")

  With cat
    .Create _
        "Provider=Microsoft.Jet.OLEDB.4.0;" & _
        "Data Source=" & _
        Environ$("temp") & "\DropMe.mdb"

    With .ActiveConnection

      Dim Sql As String

      Sql = "CREATE TABLE tblDeals (DealID INT, DealName VARCHAR(100), AssetClassID INT, DateEffective DATETIME, DateEnd DATETIME);"
      .Execute Sql

      Sql = "CREATE TABLE tblDealItems (DealItemID INT, DealID INT, CategoryID INT, ParticipantID INT, Amount INT, DateEffective DATETIME, DateEnd DATETIME);"
      .Execute Sql

      Sql = _
          " CREATE VIEW qryDates  " & _
          " AS " & _
          "  SELECT DISTINCT T1.DealID,  " & _
          "         T1.DateEffective AS tblDeals_DateEffective,  " & _
          "         ( " & _
          "          SELECT MAX(T2.DateEffective) " & _
          "            FROM tblDealItems AS T2 " & _
          "           WHERE T1.DealID = T2.DealID " & _
          "                 AND T2.DateEffective <= T1.DateEffective " & _
          "         ) AS tblDealItems_DateEffective " & _
          "    FROM tblDeals AS T1;"
      .Execute Sql

      Sql = _
      " CREATE VIEW qryDates2 " & _
      " AS " & _
      "  SELECT DISTINCT T2.DealID,  " & _
      "         T2.DateEffective AS tblDealItems_DateEffective,  " & _
      "         ( " & _
      "          SELECT MAX(T1.DateEffective) " & _
      "            FROM tblDeals AS T1 " & _
      "           WHERE T1.DealID = T2.DealID " & _
      "                 AND T1.DateEffective <= T2.DateEffective " & _
      "         ) AS tblDeals_DateEffective " & _
      "    FROM tblDealItems AS T2;"
      .Execute Sql

      Sql = _
      "INSERT INTO tblDeals VALUES (3, 'Deal 3', 3, '2010-01-01 00:00:00', '2011-07-01 00:00:00');"
      .Execute Sql
      Sql = _
      "INSERT INTO tblDeals VALUES (3, 'Deal 3', 2, '2011-07-01 00:00:00', '2011-10-01 00:00:00');"
      .Execute Sql
      Sql = _
      "INSERT INTO tblDeals VALUES (3, 'Deal 3', 1, '2011-10-01 00:00:00', NULL);"
      .Execute Sql
      Sql = _
      "INSERT INTO tblDealItems VALUES (13, 3, 3, 2, 1500, '2010-01-01 00:00:00', '2011-06-01 00:00:00');"
      .Execute Sql
      Sql = _
      "INSERT INTO tblDealItems VALUES (13, 3, 1, 2, 1500, '2011-06-01 00:00:00', '2011-06-06 00:00:00');"
      .Execute Sql
      Sql = _
      "INSERT INTO tblDealItems VALUES (13, 3, 1, 2, 6000, '2011-06-06 00:00:00', '2011-09-01 00:00:00');"
      .Execute Sql
      Sql = _
      "INSERT INTO tblDealItems VALUES (13, 3, 3, 2, 6000, '2011-09-01 00:00:00', NULL);"
      .Execute Sql

      Sql = _
      "SELECT T2.DateEffective AS [Date], '' AS Description, " & _
      "       T1.DealName, T1.AssetClassID,  " & _
      "       T2.CategoryID, T2.ParticipantID, T2.Amount " & _
      "  FROM ( " & _
      "       tblDeals AS T1 " & _
      "       INNER JOIN  " & _
      "       qryDates2 AS Q2 " & _
      "          ON T1.DateEffective = Q2.tblDeals_DateEffective " & _
      "             AND T1.DealID = Q2.DealID " & _
      "       ) " & _
      "       INNER JOIN tblDealItems AS T2 " & _
      "          ON T2.DateEffective = Q2.tblDealItems_DateEffective " & _
      "             AND T2.DealID = Q2.DealID " & _
      "UNION  " & _
      "SELECT T1.DateEffective AS [Date], '' AS Description,  " & _
      "       T1.DealName, T1.AssetClassID,  " & _
      "       T2.CategoryID, T2.ParticipantID, T2.Amount " & _
      "  FROM ( " & _
      "       tblDeals AS T1 " & _
      "       INNER JOIN  " & _
      "       qryDates AS Q1  " & _
      "          ON T1.DateEffective = Q1.tblDeals_DateEffective " & _
      "             AND T1.DealID = Q1.DealID " & _
      "       ) "
      Sql = Sql & _
      "       INNER JOIN tblDealItems AS T2 " & _
      "          ON T2.DateEffective = Q1.tblDealItems_DateEffective " & _
      "             AND T2.DealID = Q1.DealID " & _
      " ORDER " & _
      "    BY 1;"

      Dim rs
      Set rs = .Execute(Sql)
      MsgBox rs.GetString

    End With
    Set .ActiveConnection = Nothing
  End With
End Sub
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...