Проблема MS Access с DateAdd в VBA Оператор вставки с несовместимым форматом даты - PullRequest
0 голосов
/ 10 марта 2020

У меня проблемы с тем, как дата хранится в моей БД.

Мне нужно создать временную таблицу C, в которую будут вставляться X записей для каждой записи в TableA. Где Х - количество недель. Полученная таблица будет использоваться в операторе UNION с несколькими другими запросами.

Проблема заключается в том, как DateAdd создает дату для каждой новой записи. Даты изначально хранятся в формате дд / мм / гггг. Но получающийся в результате DateAdd ("ww", i, rst! [Date]) иногда будет храниться в формате mm / dd / yyyy, создавая havo c в результирующих строках 30K.

Написал VB Sub для создания таблицы, и ниже приведен пример того, как она на самом деле хранится в сравнении с тем, что ожидалось.

 </p>

<pre><code>Sub AddItems()
    Dim db as DAO.Database
    Dim rst as DAO.Recordset
    Dim Sql1, Sql2 as String

    Sql1 = "SELECT [a].*, [b].[Date], [b].[Weeks]. [b].[Rate] FROM TableA as [a] LEFT JOIN TableB as [b] WHERE [a].[GroupId] = [b].[Id] ORDER BY [b].[Date], [a].[Id];"

    Set db = CurrentDb
    Set rst = db.OpenRecordset(Sql1)

    rst.movefirst
    While NOT rst.EOF
        If rst![Weeks] > 0 Then
            For i = 1 to rst![Weeks]
                Sql2 = "INSERT INTO TableC ([ID], [CUSTOMER], [DATE], [AMOUNT]) VALUES ("
                Sql2 = Sql2 & rst![ID] & ", " & rst![CUSTOMER]
                Sql2 = Sql2 & "#" & Format(DateAdd("ww", (i - 1), Format(rst![Date], "mm/dd/yyyy")), "mm/dd/yyyy") & "#"
                Sql2 = Sql2 & ", " & rst![AMOUNT]
                Sql2 = Sql2 & ")"
                Debug.Print Format(DateAdd("ww", (i - 1), Format(rst![Date], "mm/dd/yyyy")), "mm/dd/yyyy")
                db.Execute(Sql2)
            Next i
        End If
        rst.movenext
    Wend
End Sub  
</code>

</p> RESULTING TABLE SAMPLE +-------------+------------+------------+ | Week | On Table | On Debug | Expected Data Inserted +-------------+------------+------------+ | 1 | 12/02/2019 | 02/12/2019 | Should be 2 / Dec / 2019 | | as 12/Feb | Correct | +-------------+------------+------------+ | 2 | 12/09/2019 | 09/12/2019 | Should be 9 / Dec / 2019 | | as 12/Sept | Correct | +-------------+------------+------------+ | 3 | 16/12/2019 | 16/12/2019 | Should be 16 / Dec / 2019 | | Correct | Correct | +-------------+------------+------------+

Результаты, напечатанные в «Немедленном окне», верны, но в самой таблице информация неверна. Мои примеры данных начинаются 12/12/2019 (2 декабря / 2019 г., что подтверждается селектором даты в табличном представлении в таблице A)

В окне отладки отображается правильная информация, которая должна быть сохранена, но в таблице есть неверное событие, хотя поле [ДАТА] в таблице C отформатировано с «Короткой датой» и с правилом проверки IsDate.

Без двух операторов Format результаты значительно превзошли ожидаемые. И все же результирующее поле DATE не соответствует.

ЕСТЬ ЛИ СПОСОБ ПОСЛЕДОВАТЕЛЬНО СОЗДАВАТЬ ДАТЫ И ХРАНИТЬ ИХ В СООТВЕТСТВИИ С НАСТРОЙКАМИ СИСТЕМЫ?

Ответы [ 2 ]

0 голосов
/ 10 марта 2020

Первые несколько замечаний:

  • Переменная i вообще не была объявлена, вы должны использовать Option Explicit в заголовке модуля, чтобы VBE мог предупредить вас.
  • Date - зарезервированное слово, поэтому я переименовал его в YourDate.
  • Переменная sql1 была неявно определена как вариант типа.
  • Ваше определение SQL для переменной sql1 не было синтаксически правильным. Я исправил это и надеюсь, что это то, что вы имели в виду.
  • Я ожидаю, что ваше поле таблицы YourDate имеет тип date, а не string. Если это строка, вам нужно сначала преобразовать ее в дату в коде, или, что намного лучше, в таблицу.
  • Всегда явно использовать свойство Value, если вы неявно хотите использовать его, чтобы очистить то, что вы делаете и не назначайте объект случайно.
  • Объединение строки SQL небезопасно в случае SQL Injection. Объектно-ориентированный подход не является и он безопасен для типов.

Это должно работать так, как вы ожидаете:

Option Compare Database
Option Explicit

Sub AddItems()
    Dim sql1 As String
    sql1 = "SELECT a.*, b.YourDate, b.Weeks, b.Rate FROM TableA as a LEFT JOIN TableB as b On a.GroupId = b.Id ORDER BY b.YourDate, a.Id"

    Dim db As DAO.Database
    Set db = CurrentDb

    Dim rst As DAO.Recordset
    Set rst = db.OpenRecordset(sql1)

    rst.MoveFirst
    While Not rst.EOF
        If rst("Weeks").Value > 0 Then
            Dim i As Long
            For i = 1 To rst("Weeks").Value
                With CurrentDb().CreateQueryDef(vbNullString, _
                    "INSERT INTO TableC ([ID], [CUSTOMER], [YourDATE], [AMOUNT]) " & _
                    "VALUES (@ParID, @ParCustomer, @ParDate, @ParAmount)")
                    .Parameters("@ParID").Value = rst("ID").Value
                    .Parameters("@ParCustomer").Value = rst("CUSTOMER").Value
                    .Parameters("@ParDate").Value = DateAdd("ww", (i - 1), rst("YourDate").Value)
                    .Parameters("@ParAmount").Value = rst("AMOUNT").Value
                    .Execute dbFailOnError
                End With
            Next i
        End If
        rst.MoveNext
    Wend

    rst.Close
End Sub
0 голосов
/ 10 марта 2020

Значения даты не сохраняются в формате, если тип данных Дата . Формат предназначен только для отображения или при объединении в SQL. Поэтому попробуйте:

Sub AddItems()

    Dim db  As DAO.Database
    Dim rst As DAO.Recordset
    Dim Sql1 As String
    Dim Sql2 As String

    Sql1 = "SELECT [a].*, [b].[Date], [b].[Weeks]. [b].[Rate] FROM TableA as [a] LEFT JOIN TableB as [b] WHERE [a].[GroupId] = [b].[Id] ORDER BY [b].[Date], [a].[Id];"

    Set db = CurrentDb
    Set rst = db.OpenRecordset(Sql1)

    rst.MoveFirst
    While Not rst.EOF
        If rst![Weeks] > 0 Then
            For i = 1 to rst![Weeks]
                Sql2 = "INSERT INTO TableC ([ID], [CUSTOMER], [DATE], [AMMOUNT]) VALUES ("
                Sql2 = Sql2 & rst![ID] & ", '" & rst![CUSTOMER] & "', "
                Sql2 = Sql2 & "#" & Format(DateAdd("ww", i - 1, rst![Date]), "mm/dd/yyyy") & "#, "
                Sql2 = Sql2 & Str(rst![AMMOUNT])
                Sql2 = Sql2 & ")"
                Debug.Print Format(DateAdd("ww", i - 1, rst![Date]), "mm/dd/yyyy")
                db.Execute(Sql2)
            Next i
        End If
        rst.MoveNext
    Wend
End Sub  

Тем не менее, было бы намного проще и быстрее открыть второй набор записей для таблицы C, а затем использовать AddNew и Update добавить записи за недели.

Если ваши «даты» хранятся в виде текст , нет способа решить вашу проблему, кроме ручного редактирования, чтобы привести их в согласованный формат.

...