合并具有连续日期的记录

时间:2009-10-20 11:51:44

标签: ms-access vba

我在使用Access 2007作为前端和SQL2005作为后端的数据库中存在以下问题。

在表A中,我有以下数据结构

Table A

ID     Date            Supplier_ID   
1      10/22/2009      1              
2      10/23/2009      1             
3      10/24/2009      2   
4      10/25/2009      2           
5      10/26/2009      1

我需要合并具有连续日期和相同Supplier_ID的值,为每个连续记录增加一个新列(天),然后将数据写入表B,以便我有

Table B

ID     Date            Supplier_ID      Days
1      10/22/2009      1                2
2      10/24/2009      2                2
3      10/26/2009      1                1 

只能连续几天合并。因此,表A中的ID 5被添加到表B作为新记录。自从我使用Access VBA以来已经有一段时间了,并且想知道对此有什么正确的方法。

3 个答案:

答案 0 :(得分:2)

这里有一些ANSI-92 Query Mode语法SQL DDL和DML来重新创建表和一个可能的解决方案:

CREATE TABLE TableA 
(
 ID INTEGER NOT NULL UNIQUE, 
 [Date] DATETIME NOT NULL, 
 Supplier_ID INTEGER NOT NULL
);

INSERT INTO TableA (ID, [Date], Supplier_ID) 
SELECT DT1.ID, DT1.[Date], DT1.Supplier_ID
FROM (
      SELECT DISTINCT 1 AS ID, '2009-10-22 00:00:00' AS [Date], 1 AS Supplier_ID FROM Customers
      UNION ALL 
      SELECT DISTINCT 2, '2009-10-23 00:00:00', 1 FROM Customers        
      UNION ALL 
      SELECT DISTINCT 3, '2009-10-24 00:00:00', 2 FROM Customers 
      UNION ALL 
      SELECT DISTINCT 4, '2009-10-25 00:00:00', 2 FROM Customers          
      UNION ALL 
      SELECT DISTINCT 5, '2009-10-26 00:00:00', 1  FROM Customers
     ) AS DT1;

CREATE VIEW TableA_StartDates (Supplier_ID, start_date)
AS
SELECT T1.Supplier_ID, T1.[Date] 
  FROM TableA AS T1
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM TableA AS T2
                    WHERE T2.Supplier_ID = T1.Supplier_ID 
                          AND DATEADD('D', -1, T1.[Date]) = T2.[Date]
                  );

CREATE VIEW TableA_EndDates (Supplier_ID, end_date)
AS
SELECT T3.Supplier_ID, T3.[Date] 
  FROM TableA AS T3
 WHERE NOT EXISTS (
                   SELECT * 
                     FROM TableA AS T4
                    WHERE T4.Supplier_ID = T3.Supplier_ID 
                          AND DATEADD('D', 1, T3.[Date]) = T4.[Date]
                  );

CREATE VIEW TableA_Periods (Supplier_ID, start_date, end_date)
AS 
SELECT DISTINCT T5.Supplier_ID, 
       (
        SELECT MAX(S1.start_date)
          FROM TableA_StartDates AS S1
         WHERE S1.Supplier_ID = T5.Supplier_ID
               AND S1.start_date <= T5.[Date] 
       ),
       (
        SELECT MIN(E1.end_date)
          FROM TableA_EndDates AS E1
         WHERE E1.Supplier_ID = T5.Supplier_ID
               AND T5.[Date] <= E1.end_date
       )        
  FROM TableA AS T5;

SELECT P1.Supplier_ID, P1.start_date, P1.end_date, 
       DATEDIFF('D', P1.start_date, P1.end_date) + 1 AS Days
  FROM TableA_Periods AS P1;

答案 1 :(得分:1)

我不认为这可以在单个SQL中完成,因此您必须编写一些代码。我的第一个想法是制作某种字典(Key = SupplierID,Value =(FirstDate,LastDate))并使用一种算法来迭代表A中的数据并填充字典,类似这样(伪代码) :

records = recordset: SELECT * FROM Table A ORDER BY Date
Do Until records.EOF
   If dictionary contains records!SupplierID
       If dictionaryEntry.LastDate = records!Date - 1
           dictionaryEntry.LastDate = records!Date
       Else
           Make Table B Entry (Days = LastDate - FirstDate) and remove dictionary entry
       End If
   Else
       Create dictionary entry for this Supplier with LastDate = FirstDate = records!Date
   End If

   records.MoveNext
Loop
records.Close

Make Table B Entries for all remaining entries in the dictionary

对于字典,您可以使用Scripting.Dictionary,其值为2-Element-Array。

答案 2 :(得分:1)

您有许多业务规则和一些独特的假设。例如,TableA从不为空,在运行此

之前,TableB始终为空

无论如何,下面的代码将使用您的示例数据:

Dim rs As Recordset
Dim dbs As Database, qdf As QueryDef, strSQL As String
Set dbs = CurrentDb

Dim Supplier_ID As Integer
Dim Days As Integer
Dim FirstDate As Date
Set qdf = dbs.CreateQueryDef("", "select [Date], Supplier_ID from tableA order by [date] ")
Set rs = qdf.OpenRecordset()

Supplier_ID = rs!Supplier_ID
FirstDate = rs!Date
While Not rs.EOF
    If rs!Supplier_ID <> Supplier_ID Then
        If Supplier_ID <> 0 Then
            ' we don't want to insert the first time we run through this, so we check if Supplier_ID is not zero
            dbs.Execute ("insert into tableB ([Date], Supplier_ID, Days) select #" + Format(FirstDate, "dd-mmm-yyyy") + "#, " + Str(Supplier_ID) + ", " + Str(Days))
            Supplier_ID = rs!Supplier_ID
            FirstDate = rs!Date
            Days = 0
        End If

    End If
    Days = Days + 1
    rs.MoveNext
Wend

dbs.Execute ("insert into tableB ([Date], Supplier_ID, Days) select #" + Format(FirstDate, "dd-mmm-yyyy") + "#, " + Str(Supplier_ID) + ", " + Str(Days))

虽然你可以这样做,但Access(通常是SQL)并不是逐行比较的最佳选择。即使您可以使用cursors或上述示例的代码,维护仍然是一项挑战!