# Ошибка, генерируемая из `Switch` при разборе строки в Access - PullRequest
0 голосов
/ 09 мая 2019

Я пытаюсь сделать оператор SWITCH в Access для анализа широты и долготы GPS нескольких форматов в формате десятичных градусов

SELECT
  IIF(ISNull(a.Lat), NULL, Len(A.lat) - Len(Replace(A.lat," ", ""))) as _spaces,
  Switch(
    ISNull([_spaces]), A.Lat,
    [_spaces] = 0, CDbl(A.Lat), 
    [_spaces] = 1, CDbl(Left(A.Lat,2)) + CDbl(MID(A.Lat,4,6))/60,
    [_spaces] = 2, CDbl(Left(A.Lat,2)) + CDbl(MID(A.Lat,4,2))/60 + CDbl(RIGHT(A.Lat,LEN(A.Lat)-6))/3600,
    1=1, CDbl(A.Lat)
  ) as [Lat]
FROM AggregateTags as A

, но это возвращает #Error для всех, кроме случаев, где _spaces=0.

Итак, я решил отладить, упростив условия, пытаясь только разобрать, где _spaces равно 1 или 2. Кроме того, если мой синтаксический анализ был неправильным, _spaces=2 Я решил просто поставитьпроизвольное значение для этого условия.Я также переименовал столбец выходного результата, на всякий случай, если в ссылках была какая-то округлость.

SELECT 
 IIF(ISNull(a.Lat), NULL, Len(A.lat) - Len(Replace(A.lat," ", ""))) as _spaces,
 Switch(
    [_spaces]=2, 50.0,
    [_spaces]=1, CDbl(Left(A.Lat,2)) + CDbl(MID(A.Lat,4,6))/60
  ) as Latt
FROM AggregateTags as A

Это работает для _spaces=1, но все равно выдает #Error, где _spaces=2.

Я пытался CDbl кастинг 50.0 или 50.Я также попытался выяснить, была ли какая-то проблема с порядком оценки, исключив ссылку на объявление столбца из более раннего в запросе: SWITCH(IIF(ISNull(a.Lat), NULL, Len(A.lat) - Len(Replace(A.lat," ", "")))=2, 50.0, ...), но все равно выдается ошибка #Error где _spaces=2.То же самое происходит при замене размещения различных внутренних пар «условие + результат».

Как ни странно, я не получаю сообщение об ошибке, когда я опускаю [_spaces]=1 и у меня просто [_spaces]=2 и условие по умолчанию

SELECT 
 IIF(ISNull(a.Lat), NULL, Len(A.lat) - Len(Replace(A.lat," ", ""))) as _spaces,
 Switch(
    [_spaces]=2, CDbl(50),
    1=1, A.Lat
) as Latt
FROM AggregateTags as A

Почему выдается #Error for [_spaces]=2, когда также включено [_spaces]=1?

Пример данных для столбца lat

39 14.838
39 27 15.88
39.20628
"" (empty string)
NULL

1 Ответ

0 голосов
/ 10 мая 2019

Оператор Switch в MS Access прототипируется как Switch( expr-1, value-1 [, expr-2, value-2 ] … [, expr-n, value-n ] )

Access оценивает ВСЕ value s в операторе Switch, и если в любом из них возникает ошибка - даже если expr не совпадает - он выдает #Error, как в следующей демонстрации.

SELECT
  testing.ID as nbr,
  CDbl(LEFT(nbr,3)) as L,
  CDbl(RIGHT(nbr,3)) as R,
  SWITCH(1=1,999,0=1,CDbl(0)) as intval,
  CDbl(RIGHT(nbr,5)) as errVal,
  SWITCH(1=1,999,0=1,CDbl(RIGHT(nbr,5))) as first
FROM testing

Если единственное значение в столбце идентификатора короткого текста - «123 456», это дает результат

  --------------------------------------------------
  |   nbr   |  L  |  R  | intval | errVal |  first |
  | ---------------------------------------------- |
  | 123 456 | 123 | 456 |    999 | #Error | #Error |
  --------------------------------------------------

Очевидно, 1 = 1 всегда верно, а 0 = 1 всегда ложно. Несмотря на это, Access по-прежнему оценивает оба «значения».

Подать еще одну запись в «Доступ тупой»


Что касается моего парсера, все мои координаты находятся в Северной Америке к западу от Скалистых гор, поэтому все латы составляют 2 цифры перед десятичной точкой, а все длинные - отрицательные 3 цифры. Более надежный синтаксический анализатор будет находить позиции каждого из пробелов и соответственно разбивать числа, а также может искать и исключать символы (°, ' и ").

Из-за сумасшествия, которое является методом оценки SWITCH в отношении генерации ошибок, я переключился на IIF.

SELECT 
  IIF(ISNull(a.Lat), NULL, Len(A.lat) - Len(Replace(A.lat," ", ""))) AS _Tspaces,
  IIF(ISNull(a.Lat), NULL, Len(A.lat) - Len(Replace(A.lat," ", ""))) AS _Gspaces,
  IIF(
    ISNull([_Tspaces]), NULL, IIF(
      [_Tspaces]=1, CDbl(Left(A.Lat,2)) + CDbl(RIGHT(A.Lat,6))/60, IIF(
        [_Tspaces]=2, CDbl(Left(A.Lat,2)) + CDbl(MID(A.Lat,4,2))/60 + CDbl(RIGHT(A.Lat,LEN(A.Lat)-6))/3600, IIF(
          [_Tspaces]=0, CDbl(A.Lat), A.Lat
        )
      )
    )
  ) AS Latitude,
  -1*IIF(
    ISNull([_Gspaces]), NULL, IIF(
      [_Gspaces]=1, ABS(CDbl(Left(A.Long,4))) + CDbl(RIGHT(A.Long,7))/60, IIF(
        [_Gspaces]=2, ABS(CDbl(Left(A.Long,2))) + CDbl(MID(A.Long,5,2))/60 + CDbl(RIGHT(A.Long,LEN(A.Long)-7))/3600, IIF(
          [_Gspaces]=0, ABS(CDbl(A.Long)), A.Long
        )
      )
    )
  ) AS Longitude
FROM AggregateTags AS A;
...