MS Access с SQL Server серверное обновление завершается без ошибок - PullRequest
3 голосов
/ 21 марта 2019

Этот простой оператор VBA не работает должным образом:

strSQl = "UPDATE Inventory SET NumberOfBlocks = BlocksReserved, LastUser = 'Me' WHERE InventoryID = 1234;"
CurrentDb.Execute strSQl, dbFailOnError + dbSeeChanges

LastUser обновляется, но NumberOfBlocks остается неизменным, ошибки нет.

Если я запускаю этот оператор в SSMS или какЗапрос доступа, он работает.

Если я использую переменную в операторе VBA ... "SET NumberOfBlocks =" & intBlocksReserved & ", ..., это работает.

Константа работает:... "SET NumberOfBlocks = 555" ...

И этот тоже работает : NumberOfBlocks = (BlocksReserved * 1)

NumberOfBlocks и BlocksReserved оба являются smallintи не NULL; запись имеет поле timestamp / rowversion.

Среда: Access 2016 с бэкэндом SQL 2016.

Любые идеи, почему мое первоначальное утверждение молча терпит неудачу? Спасибо!


Дальнейшее тестирование подтверждает мои предыдущие выводы:

  1. Создание новой базы данных Access, инвентаризация таблицы: ID (AutoNumber, PK), NumberOfBlocks (Integer), BlocksReserved (Integer), LastUser (Краткий текст 10)
  2. Создан таблe в SQL Server:

    [ID] [int] IDENTITY (1,1) NOT NULL, [NumberOfBlocks] [smallint] NULL, [BlocksReserved] [smallint] NULL, [LastUser] nvarchar NULL, [RV] [отметка времени] NOT NULL

  3. Установить идентификатор как первичный ключ, связанную таблицу SQL, ввести тестовые данные в обоих.

  4. Выполнить точно так жекод в обеих таблицах (изменилось только имя таблицы):

    Dim strSQl As String

    strSQl = "Инвентаризация UPDATE SET NumberOfBlocks = BlocksReserved, LastUser = 'Me';" CurrentDb.Execute strSQl,dbFailOnError + dbSeeChanges

Результат:

Таблица локального доступа: NumberOfBlocks = BlocksReserved, LastUser = 'Me'

Связанная таблица SQL: NumberOfBlocks без изменений, LastUser= 'Я'


Дополнительные примечания:

  • Изменение типа данных в SQL Server на int (вместо smallint) не имело значения.
  • Однако явное преобразование поля сработало:

    ... SET NumberOfBlocks = CInt (BlocksReserved) ...

  • так же, как

    ... SET NumberOfBlocks = (BlocksReserved * 1) ...

Я думаю, это превращает мой пост из вопроса в хедз-ап ...

Ответы [ 2 ]

1 голос
/ 22 марта 2019

Это довольно интересно. Я могу воспроизвести его с помощью Access 2010, SQL Server 2008 R2, ODBC Driver 17 для SQL Server.

Но только , если столбец (N) VARCHAR включен в запрос UPDATE!
UPDATE AAA SET Smallint2 = Smallint1, Int2 = Int1; работает.

CREATE TABLE AAA (
    ID int IDENTITY(1,1) NOT NULL, 
    Smallint1 SMALLINT NULL, 
    Smallint2 SMALLINT NULL, 
    Int1 INT NULL,
    Int2 INT NULL,
    foo NVARCHAR(255) NULL,
    RV TIMESTAMP NOT NULL,

    CONSTRAINT PK_AAA PRIMARY KEY (ID)
)
GO

INSERT AAA (Smallint1, Smallint2, Int1, Int2, foo) 
VALUES (1, 0, 77, 9999, 'asdf'), 
       (3456, NULL, NULL, 1234, 'null')

Access-VBA:

Sub TestAAA()

    Dim strSql As String

    strSql = "UPDATE AAA SET Smallint2 = Smallint1, Int2 = Int1;"
    CurrentDb.Execute strSql, dbFailOnError + dbSeeChanges

    Stop
    ' Requery table => UPDATE was successful!

    ' Edit and save values in Smallint1 / Int1

    strSql = "UPDATE AAA SET Smallint2 = Smallint1, Int2 = Int1, foo = 'with NVARCHAR';"
    CurrentDb.Execute strSql, dbFailOnError + dbSeeChanges

    Stop
    ' Requery => Smallint2 / Int2 are not updated, "foo" is!

    strSql = "UPDATE AAA SET Smallint2 = CInt(Smallint1), Int2 = CLng(Int1), foo = 'with Conversion';"
    CurrentDb.Execute strSql, dbFailOnError + dbSeeChanges

    ' Requery => Smallint2 / Int2 are updated!

End Sub

Результаты:

  • исходное состояние
  • после первого обновления
  • после ручного редактирования и второго обновления
  • после третьего обновления
+----+-----------+-----------+-----------+-----------+-----------------+
| ID | Smallint1 | Smallint2 |   Int1    |   Int2    |       foo       |
+----+-----------+-----------+-----------+-----------+-----------------+
| 1  | 1         | 0         | 77        | 9999      | asdf            |
| 2  | 3456      |           |           | 1234      | null            |
|    |           |           |           |           |                 |
| ID | Smallint1 | Smallint2 | Int1      | Int2      | foo             |
| 1  | 1         | 1         | 77        | 77        | asdf            |
| 2  | 3456      | 3456      |           |           | null            |
|    |           |           |           |           |                 |
| ID | Smallint1 | Smallint2 | Int1      | Int2      | foo             |
| 1  | 222       | 1         | 988888888 | 77        | with NVARCHAR   |
| 2  | 333       | 3456      | 999999999 |           | with NVARCHAR   |
|    |           |           |           |           |                 |
| ID | Smallint1 | Smallint2 | Int1      | Int2      | foo             |
| 1  | 222       | 222       | 988888888 | 988888888 | with Conversion |
| 2  | 333       | 333       | 999999999 | 999999999 | with Conversion |
+----+-----------+-----------+-----------+-----------+-----------------+
1 голос
/ 21 марта 2019

Дальнейшие тесты подтвердили, что это ошибка в Выполнить команду при следующих условиях:

  • Это оператор UPDATE, в котором одно целое поле назначено другому, напримерas SET FieldA = FieldB (тот же числовой тип данных)
  • Это связанная таблица в SQL Server.

Тот же оператор SQL будет работать нормально

  • с таблицей в Access или
  • при использовании в запросе.

Протестированные обходные пути:

  • Явное преобразование поля: SET FieldA = CInt (FieldB) ... (или CLng ...)
  • Использовать любой расчет: SET FieldA = FieldB * 1
  • Использовать переменную: SET FieldA = "& intFieldB
...