我在使用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以来已经有一段时间了,并且想知道对此有什么正确的方法。
答案 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或上述示例的代码,维护仍然是一项挑战!