Excel этот запрос не возвращает данные

  • Remove From My Forums
  • Question

Answers

  • I’ve had another look at the page in question, in comparison with a working web page.

    The only thing I have spotted is related to the Div tags.  In the working one the all the referencable tables have div tags with an id like this

          <div id=»yfi_market_info»><div id=»yfi_market_summary»>

    However I have noticed that although the page in question uses this

          <div class=»panel» id=»portfoliopanel» style=»clear:both; padding:6px; z-index:1; margin:0 10px»>

    it is nested inside another <div> with no id.  It appears that this also repeated elsewhere and may explain why the first div with an id doesn’t return what you were expecting. 

    It may also be why the Web Query tool cannot identify blocks that appear to be coded correctly.  Pure speculation but if the divs are not structured with ids the query will not look inside the div thus making any divs nested inside it and it’s content
    invisible.


    G North MCT

    • Marked as answer by

      Friday, October 14, 2011 1:56 AM

Если требуется регулярно обращаться к обновляемым данным с веб-страницы, создайте веб-запрос. На рис. 1 представлен сайт https://news.yandex.ru, показывающий курс доллара. [1]

%d1%80%d0%b8%d1%81-1-%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b4%d0%b8%d0%b0%d0%bb%d0%be%d0%b3%d0%be%d0%b2%d0%be%d0%b3%d0%be-%d0%be%d0%ba%d0%bd%d0%b0-%d1%81

Рис. 1. Использование диалогового окна Создание веб-запроса для указания данных, которые следует импортировать; чтобы увеличить изображение кликните на нем правой кнопкой мыши и выберите Открыть картинку в новой вкладке

Скачать заметку в формате Word или pdf, примеры в формате Excel

Термин «веб-запрос» немного неточен, так как с его помощью можно получать данные не только из Сети. Можно также выполнять веб-запрос к HTML-файлу, расположенному на локальном компьютере, или к файлу, хранящемуся на сетевом сервере либо на веб-сервере в Интернете. Чтобы получить информацию с веб-сервера, необходимо подключиться к Интернету. Когда данные получены, соединение с Интернетом для работы с ними больше не нужно (конечно, если вы не собираетесь обновлять эти данные).

Создать веб-запрос, обеспечивающий получение информации, которую позже можно будет обновить одним щелчком мыши, можно следующим образом.

  1. Выполните команду Данные –> Получение внешних данных –> Из Интернета, чтобы открыть диалоговое окно Создание веб-запроса.
  2. В поле Адрес введите URL сайта и нажмите Пуск. В нашем примере (рис. 1) изображена веб-страница, расположенная по адресу https://news.yandex.ru/quotes/1.html. Обратите внимание: в диалоговом окне Создание веб-запроса открывается браузер (Internet Explorer). В нем вы можете щелкать на ссылках и переходить по сайту, пока не найдете интересующие вас данные. Когда веб-страница отображается в окне Создание веб-запроса, вы видите один или несколько желтых квадратов со стрелками, соответствующих таблицам, находящимся на странице. Еще один такой же квадрат будет соответствовать странице целиком.
  3. Если щелкнуть на желтом квадрате со стрелкой, он превращается в зеленый флажок, указывающий, что данные этой таблицы будут импортированы. К сожалению, таблицу с курсами валют нельзя выделить, поэтому единственный выход — импортировать страницу целиком.
  4. Нажмите Параметры, чтобы выбрать формат импорта данных и иные настройки.
  5. Нажмите кнопку Импорт, чтобы отобразить диалоговое окно Импорт данных. Укажите местоположение для импортированной информации. Это может быть, как ячейка на актуальном листе, так и новый лист. Нажмите Свойства, если хотите изменить настройки импорта по умолчанию.
  6. Нажмите Ok, и Excel импортирует данные.

Результат импорта (рис. 2) не совсем то, чего мы хотели. Нас интересовала только таблица валют, а веб-запрос вернул страницу целиком. По умолчанию импортированные данные являются веб-запросом. Чтобы обновить информацию, щелкните правой кнопкой мыши на любой ячейке в импортированном диапазоне и в контекстном меню выполните команду Обновить.

%d1%80%d0%b8%d1%81-2-%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b5%d0%bd%d0%bd%d0%b0%d1%8f-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e

Рис. 2. Информация, полученная с помощью веб-запроса

Если вы не собираетесь создавать обновляемый запрос, укажите это в шаге 5 приведенного выше порядка действий. В диалоговом окне Импорт данных нажмите кнопку Свойства и снимите флажок Сохранить определение запроса.

Встроенная в Excel возможность работы с веб-запросами позволяет находить в HTML-документе таблицы (обозначаемые HTML-тегом <TABLE>). Однако веб-дизайнеры для отображения табличной информации все чаще пользуются каскадными таблицами стилей (CSS). Как понятно из данного примера, Excel не распознает такие таблицы и не показывает желтого квадрата со стрелкой, поэтому получить таблицу вы не сможете — вам может потребоваться получить целый документ, а потом удалить (или скрыть) все данные, кроме интересующей вас таблицы. 

Еще один способ отобразить данные с веб-страницы на рабочем листе напрямую открыть URL в Excel, воспользовавшись командой Файл –> Открыть. Просто введите URL полностью в поле Имя файла и нажмите Открыть (рис. 2). Результаты могут различаться в зависимости от макета веб-страницы. Как правило, итог удовлетворительный. Иногда вы получаете немного лишней информации. Обратите внимание: такие данные не обновляются. Если информация на веб-странице изменится, нужно будет закрыть книгу и снова воспользоваться командой Файл –> Открыть. Мне не удалось этого сделать. Excel сначала писал, что открывает страницу в режиме защищенного просмотра, долго работал, а потом выдал, что книга повреждена, и открыть ее нельзя((

[1] По материалам книги Джон Уокенбах. Excel 2013. Трюки и советы. – СПб.: Питер, 2014. – С. 194–196.

timist

2 / 2 / 0

Регистрация: 03.06.2012

Сообщений: 23

1

21.01.2013, 16:23. Показов 4733. Ответов 22

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Странная ситуация с SQL запросом.
Есть база данных, из которой SQL запросом вытаскиваю результаты продаж за один день в Excel-таблицу.
Данные в формате «Фирма»; «Направление»; «Кол-во»; «Сумма». Запрос работает правильно, проверено много раз.
Вот только во время распродаж, когда много покупок попадаются дни, когда SQL запрос вытаскивает не все данные за день. Какой то зависимости найти не могу, так как бывает что запросом получаю ~ 150 записей, а иногда и 100 не проходят. Больше 200 записей быть физически не может, т.к. фирм меньше.
Может кто встречался с такой ситуацией, буду рад любой подсказке. С VBA не очень силен, это моя первая работа.

Сам SQL запрос.

Visual Basic
1
2
3
4
5
6
7
8
9
10
  strS(1) = "SELECT "
  strS(1) = strS(1) + "p1.prop_name, p2.prop_name, "
  strS(1) = strS(1) + "Sum (Account_item.quantity), Sum(Account_item.ruble_price * Account_item.quantity) "
  strS(1) = strS(1) + "FROM Account_item, Account, goods INNER JOIN cross_property cp1 on (goods.ID=cp1.goods_id) "
  strS(1) = strS(1) + "INNER JOIN properties p1 on (cp1.prop_id=p1.id  AND p1.parent_id ='1997-06-30 23:25:50.671498') "
  strS(1) = strS(1) + "INNER JOIN cross_property cp2 on (goods.ID=cp2.goods_id) "
  strS(1) = strS(1) + "INNER JOIN properties p2 on (cp2.prop_id=p2.id  AND p2.parent_id = '1997-07-06 15:48:53.001999') "
  strS(1) = strS(1) + "WHERE ACCOUNT.ID = Account_item.account_id And Account_item.goods_id = goods.ID AND Account.state='C' " '
  strS(1) = strS(1) + "and ACCOUNT.datedoc = '" & Format(strCurrentDay, "yyyy-mm-dd") & "' and Account.deleted = '1' " '2011-03-14' "
  strS(1) = strS(1) + "GROUP BY p1.prop_name,  p2.prop_name"

Обработка запроса

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
  
  Dim Storage As Variant
 
  Dim wsStat As Workspace, coStat As Connection, rstRecord As Recordset, rstRec As Recordset, strS(7) As String
  Dim iCount As Long
 
  Set rstRec = coStat.OpenRecordset(strS(iNapr), dbOpenDynamic)
  rstRec.MoveLast
  iCount = Abs(rstRec.RecordCount)
  If iCount = 0 Then Exit For
  rstRec.MoveFirst
  Storage = rstRec.GetRows(iCount)

Пробовал этот запрос делать в iSQL отрабатывает всегда полностью. Получается проблема в посылке запроса из Excel’я? Я в тупике



0



Модератор

Эксперт функциональных языков программированияЭксперт Python

34702 / 19224 / 4037

Регистрация: 12.02.2012

Сообщений: 32,180

Записей в блоге: 13

21.01.2013, 18:26

2

Цитата
Сообщение от timist
Посмотреть сообщение

Получается проблема в посылке запроса из Excel’я?

— не исключено. Проверь все переменные VBA, которые входят в SQL-запрос.



0



2 / 2 / 0

Регистрация: 03.06.2012

Сообщений: 23

21.01.2013, 20:24

 [ТС]

3

Я в VBA не силен, поэтому не очень понял про какие переменные VBA идет речь.
Если о переменных которые входят в запрос, то в вышеупомянутом запросе переменная только ДАТА за которую собираются данные. Почти всегда собираются данные правильно (именно за тот день который указан ), в месяц не больше 5-ти дней данные не полные.
Если о переменных среды VBA, то можно поподробнее что и где рыть.



0



Модератор

Эксперт функциональных языков программированияЭксперт Python

34702 / 19224 / 4037

Регистрация: 12.02.2012

Сообщений: 32,180

Записей в блоге: 13

21.01.2013, 20:47

4

Да, там единственная переменная strCurrentDay. Покажи полный код обработки запроса.



1



Alex77755

11482 / 3773 / 677

Регистрация: 13.02.2009

Сообщений: 11,145

22.01.2013, 10:48

5

Visual Basic
1
iCount = Abs(rstRec.RecordCount)

Встречается отрицательное количество записей?



0



timist

2 / 2 / 0

Регистрация: 03.06.2012

Сообщений: 23

22.01.2013, 13:31

 [ТС]

6

Я ограничился этой частью, т.к. проблема где-то тут.
Переменная rstRec получает не все записи (я в окне Watches это проверял), а в массив Storage передает все свои данные полностью. Далее из массива заполняется Excelевская таблица, но там тоже все правильно отрабатывает.
Игрался с переменной coStat.QueryTimeout = 500, но бесполезно, в один день, когда много продаж было запрос так и не выполняется — выскакивает ошибка Run-time error 3669

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 Set wsStat = CreateWorkspace("", "", "", dbUseODBC)
  Set coStat = wsStat.OpenConnection("", , , "ODBC;Database=Mainbase;UID=onstore;PWD=00000;DSN=mybase")
  coStat.QueryTimeout = 500
 
  Worksheets(strCurrentMonth).Visible = True
  Worksheets(strCurrentMonth & "_Ä").Visible = True
 
  For iNapr = 1 To 2
  Debug.Print strS(iNapr), TypeName(strS(iNapr));
  Set rstRec = coStat.OpenRecordset(strS(iNapr), dbOpenDynamic)
 
  rstRec.MoveLast
  iCount = Abs(rstRec.RecordCount)
  If iCount = 0 Then Exit For
  rstRec.MoveFirst
  Storage = rstRec.GetRows(iCount)
    
' Иногда значение переменной rstRec.RecordCount было больше чем фактическое кол-во записей, 
' соответственно и в массив передавалось меньше, поэтому переменной iCount 
' присваивается фактическая размерность массива  
  iCount = UBound(Storage, 2)
  
  For i = 0 To iCount
' Далее идет обработка записей массива



0



11482 / 3773 / 677

Регистрация: 13.02.2009

Сообщений: 11,145

22.01.2013, 13:41

7

Пробовал этот запрос делать в iSQL отрабатывает всегда полностью

Ну так, вроде можно оставить запрос в базе и пользоваться его результатами?



0



mc-black

2784 / 716 / 106

Регистрация: 04.02.2011

Сообщений: 1,443

22.01.2013, 14:05

8

Довольно странно выглядит выражение:

Visual Basic
1
Format(strCurrentDay, "yyyy-mm-dd")

Вероятно строковое представление даты переформатируется так, будто работаем с типом Date. Может попробовать как-то так:

Visual Basic
1
Format(CDate(strCurrentDay), "yyyy-mm-dd")

Второе замечание по стилю. В VBA конкатенацию (объединение) строк пишут символом амперсанда ‘&’, а не ‘+’ во избежиния путаницы с типами данных.



0



Catstail

Модератор

Эксперт функциональных языков программированияЭксперт Python

34702 / 19224 / 4037

Регистрация: 12.02.2012

Сообщений: 32,180

Записей в блоге: 13

22.01.2013, 15:12

9

Я же писал — покажи полный код обработки (а не кусок из середины). Так вот: не используй счетчик записей (он не всегда достоверен), лучше используй итерационный цикл:

Visual Basic
1
2
3
4
5
6
7
   Do whie Not Rs.EOF
 
       ' обработка
 
       rs.moveNext
 
   Loop

Добавлено через 50 минут

Цитата
Сообщение от mc-black
Посмотреть сообщение

Довольно странно выглядит выражение:

— самое правильное — писать вот так:

Visual Basic
1
Format$(CDate(strCurrentDay), "yyyy-mm-dd")

Все функции без доллара возвращают тип Variant (с долларом — строковый). Но все упорно пишут без доллара…



0



2784 / 716 / 106

Регистрация: 04.02.2011

Сообщений: 1,443

22.01.2013, 15:18

10

Цитата
Сообщение от Catstail
Посмотреть сообщение

Все функции без доллара возвращают тип Variant (с долларом — строковый). Но все упорно пишут без доллара…

По большому счеты Вы правы. Там неявное преобразование типа при конкатенации с ‘&’ или с явным объявлением переменных, поэтому обычно проходит без ‘$’.



0



timist

2 / 2 / 0

Регистрация: 03.06.2012

Сообщений: 23

22.01.2013, 16:13

 [ТС]

11

Цитата
Сообщение от Alex77755
Посмотреть сообщение

Ну так, вроде можно оставить запрос в базе и пользоваться его результатами?

Изначально, была таблица и торговая программа, в торговой программе делался отчет за день и руками данные заносились в таблицу. Сейчас из Excel делает запрос в базу данных и оттуда вытаскивает все продажи и автоматически заносит в нужную дату и соответствующую фирму.
Вы предлагаете вернуться обратно. Я тоже не против , только фирм много и директора хотят автоматически собирать статистику.

Добавлено через 3 минуты

Цитата
Сообщение от Alex77755
Посмотреть сообщение

Встречается отрицательное количество записей?

Продажи или есть (всегда) или их нет (1 января). Возвраты это тоже продажи, только данные там отрицательные. Обрабатываются нормально. По небольшим магазинам собирал статистику за несколько лет. Почти всегда все правильно.

Добавлено через 3 минуты

Цитата
Сообщение от mc-black
Посмотреть сообщение

Довольно странно выглядит выражение:

Visual Basic
1
Format(strCurrentDay, "yyyy-mm-dd")

Вероятно строковое представление даты переформатируется так, будто работаем с типом Date. Может попробовать как-то так:

Visual Basic
1
Format(CDate(strCurrentDay), "yyyy-mm-dd")

Второе замечание по стилю. В VBA конкатенацию (объединение) строк пишут символом амперсанда ‘&’, а не ‘+’ во избежиния путаницы с типами данных.

Поначалу перепробовал разные преобразования, чтобы запрос заработал. Сейчас файл работоспособный, только в некоторые дни продажи не стыкуются.
На будущее учту замечания. Спасибо.

Добавлено через 2 минуты

Цитата
Сообщение от Catstail
Посмотреть сообщение

Да, там единственная переменная strCurrentDay. Покажи полный код обработки запроса.

Здесь можно большие куски выкладывать вставкой? или надо файлик присоединять?

Добавлено через 2 минуты

Цитата
Сообщение от mc-black
Посмотреть сообщение

По большому счеты Вы правы. Там неявное преобразование типа при конкатенации с ‘&’ или с явным объявлением переменных, поэтому обычно проходит без ‘$’.

Про это я вообще был не в курсе. В основном все методом подгона подсмотренного кода и методом тыка

Добавлено через 8 минут

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  Set wsStat = CreateWorkspace("", "", "", dbUseODBC)
  Set coStat = wsStat.OpenConnection("", , , "ODBC;Database=Mainbase;UID=onstore;PWD=000000;DSN=mybase")
  coStat.QueryTimeout = 500
 
  Worksheets(strCurrentMonth).Visible = True
  Worksheets(strCurrentMonth & "_Ä").Visible = True
 
  For iNapr = 1 To 2
  Debug.Print strS(iNapr), TypeName(strS(iNapr));
  Set rstRec = coStat.OpenRecordset(strS(iNapr), dbOpenDynamic)
 
  rstRec.MoveLast
  iCount = Abs(rstRec.RecordCount)
  If iCount = 0 Then Exit For
  rstRec.MoveFirst
  Storage = rstRec.GetRows(iCount)
  
  Worksheets(strCurrentMonth).Activate
  Worksheets(strCurrentMonth).Rows("1:2000").Hidden = False
  noData = True
  
  iCount = UBound(Storage, 2)
  
  For i = 0 To iCount
    With Worksheets(strCurrentMonth).Range("b:b")
 
      Set c = .Find("start" & Storage(0, i), LookIn:=xlValues)
      str4 = "b" + CStr(c.Row) + ":"
      Set c = .Find("new" & Storage(0, i), LookIn:=xlValues)
      str4 = str4 + "b" + CStr(c.Row) + ""
    End With
    With Worksheets(strCurrentMonth).Range(str4)
       
      Set c = .Find(Storage(1, i), LookAt:=xlWhole, LookIn:=xlValues)  'Ïîèñê ôèðìû â òàáëèöå
      If c Is Nothing Then
        AddBrendToStat   'Äîáàâëåíèå íîâîé ôèðìû
        Set c = .Find(Storage(1, i), LookIn:=xlValues)  'Ïîèñê äîáàâëåííîé íîâîé ôèðìû
      End If
      iRow = c.Row
      iColums = CInt(Format(strCurrentDay, "dd")) + 4
      Cells(iRow, iColums).Value = Storage(2, i)  'Ââîä ïðîäàííîãî êîëè÷åñòâà
      Cells(iRow + 1, iColums).Value = (Storage(3, i) / bytCurs) 'Ââîä ïðîäàííîé ñóììû
          
  ' ïîäñ÷åò ñóìì ïî ýòàæàì
      With Worksheets("Ôèëèàë")
      Select Case iNapr
        Case 1
          Set c = .Range("a:b").Find("Ôèðìû")
          strStartGroup = "a" + CStr(c.Row + 1) + ""
          Set c = .Range("a:b").Find("finish")
          strEndGroup = "b" + CStr(c.Row - 1) + ""
        Case 2
          Set c = .Range("e:f").Find("Ôèðìû")
          strStartGroup = "e" + CStr(c.Row + 1) + ""
          Set c = .Range("e:f").Find("finish")
          strEndGroup = "f" + CStr(c.Row - 1) + ""
        End Select
        Set c = Worksheets("Ôèëèàë").Range(strStartGroup & ":" & strEndGroup).Find(Storage(1, i), LookAt:=xlWhole, LookIn:=xlValues)
        sngHall(1, Worksheets("Ôèëèàë").Cells(c.Row, c.Column + 1).Value) = sngHall(1, Worksheets("Ôèëèàë").Cells(c.Row, c.Column + 1).Value) + CSng(Storage(3, i))
      End With
    
    End With
  Next i

Надеюсь этого хватит. Дальше идет запрос по наличным и кредитным оплатам. Собственно с ними я результат и сравниваю. Ну и конечно торговой программой перепроверяю.



0



Catstail

Модератор

Эксперт функциональных языков программированияЭксперт Python

34702 / 19224 / 4037

Регистрация: 12.02.2012

Сообщений: 32,180

Записей в блоге: 13

22.01.2013, 18:11

12

Попробуй отказаться от цикла по i (со счетчиком) и реализуй обработку так:

Visual Basic
1
2
3
4
5
6
7
8
9
   rstRec.MoveFirst
 
   Do While Not rstRec.EOF
 
       ' далее твои строки 25 - 62
 
       rtsRec.MoveNext
 
   Loop

Скорее всего, ошибка исчезнет. А причина ошибки, мне кажется, в том, что при выполнении кода:

Visual Basic
1
2
  rstRec.MoveLast
  iCount = Abs(rstRec.RecordCount)

SQL-сервер недоформировал recordset. Поэтому RecordCount может быть неактульным (меньше реального)



0



timist

2 / 2 / 0

Регистрация: 03.06.2012

Сообщений: 23

23.01.2013, 10:49

 [ТС]

13

Цитата
Сообщение от Catstail
Посмотреть сообщение

Попробуй отказаться от цикла по i (со счетчиком) и реализуй обработку так:

Visual Basic
1
2
3
4
5
   rstRec.MoveFirst
   Do While Not rstRec.EOF
       ' далее твои строки 25 - 62
       rtsRec.MoveNext
   Loop

Скорее всего, ошибка исчезнет. А причина ошибки, мне кажется, в том, что при выполнении кода:

Visual Basic
1
2
  rstRec.MoveLast
  iCount = Abs(rstRec.RecordCount)

SQL-сервер недоформировал recordset. Поэтому RecordCount может быть неактульным (меньше реального)

Я результат запроса передаю в массив

Visual Basic
1
Storage = rstRec.GetRows(iCount)

а потом работаю с четырьмя полями каждой записи, а как обращаться к необходимому полю каждой записи переменнойrstRec я не знаю. Возможно ли это?

ЗЫ У меня были случаи когда

Visual Basic
1
iCount = Abs(rstRec.RecordCount)

равнялась например 120, а при передачи данных в массив

Visual Basic
1
Storage = rstRec.GetRows(iCount)

размерность массива была 120, но данных там почему то содержалось только 100. Поэтому чтобы массив обрабатывался без ошибок я добавил

Visual Basic
1
iCount = UBound(Storage, 2)



0



11482 / 3773 / 677

Регистрация: 13.02.2009

Сообщений: 11,145

23.01.2013, 13:17

14

timist,
rstRec.RecordCount — это не количество продаж-возвратов, а количество записей в наборе.
И оно не может быть отрицательным! Запись бдет с положительным номером, но с отрицательным значением количества.
По поводу базы: я же не говорил, о возврате к торговой программе, а о самой базе!
В каком она формате? Можно открать базу в соответсвующей программе, создать и сохранить нужный запрос. А из ексела вызвать готовый запрос с передачей параметра. Я так как-то делал



0



2 / 2 / 0

Регистрация: 03.06.2012

Сообщений: 23

23.01.2013, 14:04

 [ТС]

15

Цитата
Сообщение от Alex77755
Посмотреть сообщение

timist,
rstRec.RecordCount — это не количество продаж-возвратов, а количество записей в наборе.
И оно не может быть отрицательным! Запись бдет с положительным номером, но с отрицательным значением количества.
По поводу базы: я же не говорил, о возврате к торговой программе, а о самой базе!
В каком она формате? Можно открать базу в соответсвующей программе, создать и сохранить нужный запрос. А из ексела вызвать готовый запрос с передачей параметра. Я так как-то делал

Про RecordCount: я именно это и хотел сказать, но не точно высказался. У вас лучше получилось ответить на свой вопрос . Т.к. у меня еще нет опыта, то iCount = Abs(rstRec.RecordCount) подглядел у кого-то в примерах.
По базе: формат .db, по поводу запроса в базе я читал, но прав у меня на это нет, поэтому я даже и не мучился.



0



Alex77755

11482 / 3773 / 677

Регистрация: 13.02.2009

Сообщений: 11,145

23.01.2013, 18:02

16

Перед определением количества записей в наборе попробуй сделать не один переход в начало, а сначала в конец, а потом в начало

Visual Basic
1
2
rstRec.MoveLast
rstRec.MoveFirst



0



Модератор

Эксперт функциональных языков программированияЭксперт Python

34702 / 19224 / 4037

Регистрация: 12.02.2012

Сообщений: 32,180

Записей в блоге: 13

23.01.2013, 18:22

17

Цитата
Сообщение от Alex77755
Посмотреть сообщение

Перед определением количества записей в наборе попробуй сделать

— да зачем его определять? Лучше сразу цикл по recordSet-у!



0



11482 / 3773 / 677

Регистрация: 13.02.2009

Сообщений: 11,145

23.01.2013, 19:01

18

Не знаю почему. Но когда интересовался этим вопросам, то почти во всех примерах это было.
Объяснялось особенностями (читай глюками) самого инструмента



0



Эксперт MS Access

26777 / 14456 / 3192

Регистрация: 28.04.2012

Сообщений: 15,782

23.01.2013, 19:21

19

Цитата
Сообщение от Alex77755
Посмотреть сообщение

Не знаю почему. Но когда интересовался этим вопросам, то почти во всех примерах это было.
Объяснялось особенностями (читай глюками) самого инструмента

Не глюки. Особенности, да. Автор использует DAO-рекордсет, в котором только после обращения к последней записи набора, значение свойства RecordCount становится равным полному числу неудаленных записей в объекте Recordset. Поэтому для принудительного обращения к последней записи используют MoveLast. И возврат в начало MoveFirst для прохождения цикла по рекордсету.



0



timist

2 / 2 / 0

Регистрация: 03.06.2012

Сообщений: 23

26.01.2013, 12:15

 [ТС]

20

Цитата
Сообщение от Alex77755
Посмотреть сообщение

Перед определением количества записей в наборе попробуй сделать не один переход в начало, а сначала в конец, а потом в начало

Visual Basic
1
2
rstRec.MoveLast
rstRec.MoveFirst

Стал просматривать досконально переменную rstRec после запроса и после MoveLast и обнаружил, что и вправда rstRec.RecordCount после MoveLast увеличивается, в принципе в моей случае даже не надо MoveFirst делать, после него уже ничего не меняется.
К сожалению, ошибка не исправилась, данные получаются не полностью.

Но я заметил, что после запроса счетчик записей rstRec.RecordCount становится отрицательным, после MoveLast увеличивается и становится положительным: тогда данные получаются полностью. А вот когда rstRec.RecordCount остается почему то отрицательным, тогда 100% что часть данных потеряется.

Добавлено через 4 минуты

Цитата
Сообщение от Catstail
Посмотреть сообщение

— да зачем его определять? Лучше сразу цикл по recordSet-у!

А как мне обратиться к каждой записи? Когда я передаю данные в массив, то обрабатываю их как Storage(x, y). В переменной rstRec не нашел всех значений запроса.
Например, как обратиться к записи Storage(2, 14) в случае цикла по recordSet?



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

26.01.2013, 12:15

20

Доброе утро,

У меня есть полуфункциональный SQL-запрос для извлечения данных из IBM AS / 400 в Microsoft Excel. Данные отображаются правильно в Microsoft Query, но когда я нажимаю «Вернуть данные», чтобы вернуть данные в Excel, я получаю следующее сообщение об ошибке:

[IBM][System i Access ODBC Driver][DB2 for i5/OS]SQ20448 - Expression not 
valid using format string specified for TIMESTAMP_FORMAT.

По сути, мой код объединяет несколько файлов, чтобы предоставить мне информацию об элементе, и использует даты для удаления дубликатов, чтобы я мог получить самые последние транзакции.

Я использую практически идентичный код для других файлов, которые работают правильно, поэтому подозреваю, что в моих исходных данных может быть неправильно отформатированная дата, что может вызвать ошибку при преобразовании даты IBM в дату, совместимую с Microsoft, с помощью функции TO_DATE. Я знаю, что преобразование даты работает правильно, поскольку дата IBM является действительной.

У меня вопрос: как я могу закодировать исключение, чтобы игнорировать неправильно отформатированные данные, или как я могу вернуть данные, которые отформатированы неправильно, чтобы я мог записать исключение в свой код?

Вот мой код (надеюсь, комментарии будут полезны):

SELECT xh.ITNBR, yh.VNDNR, zh.VN35VM, yh.BUYNO, xh.Create_Date -- Item #, Vendor #, Vendor Name, Buyer, Create_Date
  FROM
   (SELECT PO_IH.ITNBR, -- Item #
           max(TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH.ACTDT,2,2))), 'MM/DD/YY')) as Create_Date -- Converts IBM date format to work with Microsoft Query
      FROM POHISTI as PO_IH, POHSTM as PO_MH 
     WHERE PO_IH.ORDNO = PO_MH.ORDNO AND
           (TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH.ACTDT,2,2))), 'MM/DD/YY')) = 
           (SELECT MIN((TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH.ACTDT,2,2))), 'MM/DD/YY'))) -- All of this chaos basically removes duplicate information and converts IBM date
              FROM POHSTM as PO_MH2
             WHERE PO_MH.ORDNO = PO_MH2.ORDNO AND
                   PO_MH.ACTDT NOT LIKE '0%' AND -- Removes dates that start with 0 (i.e. IBM's way of saying "no date")
                   PO_MH.ACTDT NOT LIKE '9%') -- Removes dates from 20th century
  GROUP BY PO_IH.ITNBR) xh
 LEFT JOIN 
   (SELECT PO_IH2.ITNBR, -- Item #
           PO_IH2.BUYNO, -- Buyer
           PO_IH2.VNDNR, -- Vendor
           (TO_DATE((CONCAT(
         CONCAT(
         (CONCAT(SUBSTRING(PO_MH2.ACTDT,4,2), '/')),
         (CONCAT(SUBSTRING(PO_MH2.ACTDT,6,2), '/'))),
         SUBSTRING(PO_MH2.ACTDT,2,2))), 'MM/DD/YY')) as Create_Date
    FROM POHISTI as PO_IH2, POHSTM as PO_MH2
   WHERE PO_IH2.ORDNO = PO_MH2.ORDNO AND
         PO_MH2.ACTDT NOT LIKE '0%' AND -- Removes dates that start with 0 (i.e. IBM's way of saying "no date")
         PO_MH2.ACTDT NOT LIKE '9%') yh -- Removes dates from 20th century
      ON xh.ITNBR = yh.ITNBR AND xh.Create_Date = yh.Create_Date
LEFT JOIN VENNAML0 zh -- Vendor Name
      ON yh.VNDNR = zh.VNDRVM

Вот результат Microsoft Query:

ITNBR           VNDNR   VN35VM          BUYNO   CREATE_DATE

A-FUL           76      HOLLAND COMP    SUSY    2016-12-06 00:00:00.000000
A-MINI          76      HOLLAND COMP    SUSY    2016-11-28 00:00:00.000000
A-SHIMBOX       76      HOLLAND COMP    SUSY    2014-10-16 00:00:00.000000
A-001           76      HOLLAND COMP    SUSY    2016-12-19 00:00:00.000000
A-002           76      HOLLAND COMP    SUSY    2016-12-19 00:00:00.000000
....

Как я уже сказал, информация отлично отображается в Microsoft Query, но когда я возвращаю ее в Excel, я получаю указанную выше ошибку. Я попытался использовать приведенные выше инструкции «НЕ НРАВИТСЯ» для устранения двух наиболее распространенных ошибок, но не знаю, как найти другие ошибки.

Мне все равно, получу ли я плохие данные, если они выгружаются в Excel. На этом этапе я могу это исправить. Но я подозреваю, что если Microsoft Query не может преобразовать дату, он не вернет данные в Excel.

Спасибо.

1 ответ

Лучший ответ

У вас есть числовое поле в формате CYYMMDD. Это общий формат даты в мире IBM i, где C — код века (0 => 19, 1 => 20, 2 => 21, …, 9 => 28). Это произошло из-за того, что большинство десятичных дат хранилось в упакованном десятичном формате с 2-значными годами до исправления проблемы 2000 года. Упакованное десятичное число всегда имеет место для нечетного числа цифр из-за конфигурации формата, но большинство дат были определены как (6,0) (длина, десятичные разряды) . Это оставило место на диске для одной дополнительной цифры слева от даты, и люди могли определить даты как (7,0) без изменения формата данных в записях. таким образом, семизначная дата родилась в результате 2000 года. Synon была первой известной мне компанией, которая сделала это в своем генераторе кода 2E. Он был довольно популярен, и формат есть везде. Он даже нашел свое место в операционной системе IBM.

Поэтому, когда SQL преобразует это в CHAR, дата типа 0951107 будет выглядеть как 951107, а когда SQL преобразует 1171107 в CHAR, это будет выглядеть как 1171107. К сожалению, NOT LIKE '9%' в какой-то момент будет ненадежным, потому что ведущая 9 может быть первая ненулевая цифра даты эры 1990 года, или это может быть дата эры 2800 года. Хуже того, часть дат 1900-х годов в CHAR могла начинаться с любых цифр от 1 до 9. Например, дата 1985/12/05 будет выглядеть как 0851205 в цифровом формате CYYMMDD. Это будет приведено к 851205. Таким образом, при работе с датами вам нужно использовать DIGITS для преобразования числа в CHAR, чтобы не потерять начальный символ 0. И вам нужно проверить поле даты на 0, что буквально равно 0000000 (а не 00/00/00, хотя это выглядит так, когда оно отформатировано с помощью EDITC (Y)).

Вот пример того, что происходит:

create table datetest
  (decdt       decimal(7,0));
insert into datetest
  values (0), (941107), (1170304), (1000101);

select substr(decdt,4,2) || '/' || 
       substr(decdt,6,2) || '/' || 
       substr(decdt,2,2), 
       decdt 
from datetest;

Приводит к:

  /  /      0
10/7 /41    941,107
03/04/17    1,170,304
01/01/00    1,000,101

Готов поспорить, ваша процедура TO_DATE() неправильно обрабатывает недопустимые даты, поскольку они почти наверняка передаются. Если вы используете digits в функции substr, вы получите что-то более разумное.

select substr(digits(decdt),4,2) || '/' || 
       substr(digits(decdt),6,2) || '/' || 
       substr(digits(decdt),2,2), 
       decdt
from datetest

Приводит к:

00/00/00    0
11/07/94    941,107
03/04/17    1,170,304
01/01/00    1,000,101

Обратите внимание, что части месяца, дня и года теперь находятся в правильном месте, и все, что вам нужно кодировать, — это дата 0, что означает отсутствие даты. В любом случае функции to_date() необходимо обнаружить недопустимую дату и либо проигнорировать ее, либо установить для нее что-то полезное, например 0001-01-01 или null.


1

jmarkmurphy
14 Ноя 2017 в 23:01

Гугл Таблицы. Что делать, если запрос QUERY не вернул резуль

book

Дата: Понедельник, 02.08.2021, 09:35 |
Сообщение № 1

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 146


Репутация:

8

±

Замечаний:
0% ±


Excel 2016

Добрый день!
Для преобразования таблиц использую функцию QUERY.

Код

={query(‘План’!A2:W;»SELECT A,B,D,I, n , sum(O)/120*100,’PL’, T,U,W WHERE E is not null AND E<>’конец таблицы’ AND U=1
GROUP BY A,B,D,I,N, T,U,W LABEL ‘PL’ », sum(O)/120*100 » «);
query(‘План’!A2:W;»SELECT A,B,D,I, n , sum(O),’PL’, T,U,W WHERE E is not null AND E<>’конец таблицы’ AND U=0
GROUP BY A,B,D,I,N, T,U,W LABEL ‘PL’ », sum(O) » «)}

Запрос делает из «горизонтальной» таблицы «вертикальную». В нем есть отбор WHERE по значению 0 или 1 в столбце U.
Если в столбце источнике отсутствует либо 0, либо 1, то соответствующая часть запроса возвращает #НД и «слетает» вся формула.

Цель – получить суммы без НДС для определенных строк. Подскажите, пожалуйста, можно ли как-то обойти эту ошибку? или надо переделать всю логику таблицы?

Спасибо.

Ссылка на файл. В файле два листа. Проблемные ячейки выделены желтым.
https://docs.google.com/spreads….0663477



С уважением,
Андрей.

Сообщение отредактировал bookПонедельник, 02.08.2021, 09:37

 

Ответить

Gustav

Дата: Понедельник, 02.08.2021, 11:18 |
Сообщение № 2

Группа: Друзья

Ранг: Старожил

Сообщений: 2398


Репутация:

985

±

Замечаний:
0% ±


начинал с Excel 4.0, видел 2.1

Думаю, Вам должна помочь функция IFERROR. Ею можно обернуть результат, возвращаемый QUERY.

Посмотрите как у меня сделана здесь обработка ситуаций, когда листы с данными для SELECT еще не существуют в природе:
http://www.excelworld.ru/forum/23-32571-212775-16-1489162865

ПОЖЕЛАНИЕ: И лучше оформлять формулы Гугл тегом VBA, а то переводчик формул с RUS на ENG в данном случае оказывает медвежью услугу и представляет содержимое формулы в неудобоваримом виде (он просто пока еще не предназначен для некоторых формул Гугл — отсюда и «каша»).


МОИ: Ник, Tip box: 41001663842605

 

Ответить

Gustav

Дата: Понедельник, 02.08.2021, 12:49 |
Сообщение № 3

Группа: Друзья

Ранг: Старожил

Сообщений: 2398


Репутация:

985

±

Замечаний:
0% ±


начинал с Excel 4.0, видел 2.1

Вот такая формула работает (в вашу таблицу тоже вставил в копию Реестра):
[vba]

Код

=QUERY({
IFERROR(query(‘План’!A2:W;»SELECT A,B,D,I,N, sum(O)/120*100,’PL’, T,U,W WHERE E is not null AND E<>’конец таблицы’ AND U=1
GROUP BY A,B,D,I,N, T,U,W LABEL ‘PL’ », sum(O)/120*100 » «);{«»»»»»»»»»»»»»»»»»»»});
IFERROR(query(‘План’!A2:W;»SELECT A,B,D,I,N, sum(O),’PL’, T,U,W WHERE E is not null AND E<>’конец таблицы’ AND U=0
GROUP BY A,B,D,I,N, T,U,W LABEL ‘PL’ », sum(O) » «);{«»»»»»»»»»»»»»»»»»»»})
};»where Col1 is not null»)

[/vba]
Как видно, вместо ошибки во внутреннем запросе вставляется однострочный массив пустых значений {«»»»»»»»»»»»»»»»»»»»} (пустых строк в нём = по кол-ву столбцов). Далее пустые строки результата удаляются во внешнем QUERY по условию «where Col1 is not null» (Col1 это в данном случае исходная колонка A).


МОИ: Ник, Tip box: 41001663842605

 

Ответить

book

Дата: Понедельник, 02.08.2021, 13:49 |
Сообщение № 4

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 146


Репутация:

8

±

Замечаний:
0% ±


Excel 2016

в вашу таблицу тоже вставил в копию Реестра

Gustav, Спасибо! Я видел Вашу формулу.
Хотелось бы сделать более компактно, т.к. реально будет не два запроса – больше.

Есть задумка к исходному массиву «приклеить» массив с нулями и единицами и уже потом обращаться через QUERY к объединенному массиву. Но что-то пошло не так…

Посмотрите, пожалуйста, на листе ВопросДляGustav. Выделено желтым.



С уважением,
Андрей.

 

Ответить

book

Дата: Понедельник, 02.08.2021, 13:55 |
Сообщение № 5

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 146


Репутация:

8

±

Замечаний:
0% ±


Excel 2016

И лучше оформлять формулы Гугл тегом VBA

Спасибо за совет. Видел, но не знал, как исправить.



С уважением,
Андрей.

 

Ответить

Gustav

Дата: Понедельник, 02.08.2021, 15:27 |
Сообщение № 6

Группа: Друзья

Ранг: Старожил

Сообщений: 2398


Репутация:

985

±

Замечаний:
0% ±


начинал с Excel 4.0, видел 2.1

Есть задумка к исходному массиву «приклеить» массив с нулями и единицами и уже потом обращаться через QUERY к объединенному массиву. Но что-то пошло не так…

Вам надо разделить SELECT и WHERE в вашей исходной формуле:
[vba]

Код

=query( { ‘План’!A2:X5;  ‘Сервис’!A2:X5 } ; «select Col1,Col2,Col3 WHERE Col2=1» )

[/vba]
на два QUERY внутри той же формулы:
[vba]

Код

=QUERY(query({‘План’!A2:X5;’Сервис’!A2:X5 };»select Col1,Col2,Col3″;0);»WHERE Col2=’1′»)

[/vba]
Обратите внимание, что я подавил заголовки во внутреннем QUERY при помощи константы 0 (а то они выходили из-под контроля за счет конкатенации первых строк), а также, что тип второго столбца во время исполнения внутреннего QUERY изменился на текстовый и теперь во внешнем QUERY надо искать не число 1, а текст ‘1’.

Вообще, будьте осторожнее со смешением в одном столбце текстовых и числовых значений — результаты могут неприятно удивлять. Тем более, раз вы генерируете некую фиктивную строку: просто оставляйте пустую строку или пробел в текстовых колонках и, например, 0 — в числовых.


МОИ: Ник, Tip box: 41001663842605

 

Ответить

book

Дата: Понедельник, 02.08.2021, 15:43 |
Сообщение № 7

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 146


Репутация:

8

±

Замечаний:
0% ±


Excel 2016

тип второго столбца во время исполнения внутреннего QUERY изменился на текстовый и теперь во внешнем QUERY надо искать не число 1, а текст ‘1’.

Это в данном случае только? или QUERY всегда так работает?



С уважением,
Андрей.

 

Ответить

book

Дата: Понедельник, 02.08.2021, 15:44 |
Сообщение № 8

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 146


Репутация:

8

±

Замечаний:
0% ±


Excel 2016

Вообще, будьте осторожнее со смешением в одном столбце текстовых и числовых значений

Да — это плохая практика. В данном случае поспешил, создавая пример. В реальных данных за этим всегда слежу.



С уважением,
Андрей.

 

Ответить

Gustav

Дата: Понедельник, 02.08.2021, 16:16 |
Сообщение № 9

Группа: Друзья

Ранг: Старожил

Сообщений: 2398


Репутация:

985

±

Замечаний:
0% ±


начинал с Excel 4.0, видел 2.1

Это в данном случае только?

В данном случае. Потому что тип столбца QUERY определяется по наиболее часто встречающемуся типу среди данных, из которых делается выборка. Если это число, то всё, что не число, отвергается. Можно изменить тип, забив в изначально числовой столбец текстовые значения в количестве, превышающем количество чисел в нём — увидите что получится: даже числа станут текстом (что у вас и происходит).

Примерно то же самое здесь: http://www.excelworld.ru/forum/23-43396-287359-16-1573720806


МОИ: Ник, Tip box: 41001663842605

 

Ответить

book

Дата: Понедельник, 02.08.2021, 16:23 |
Сообщение № 10

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 146


Репутация:

8

±

Замечаний:
0% ±


Excel 2016

Gustav, большое спасибо! Очень ценная помощь и подробные объяснения.



С уважением,
Андрей.

 

Ответить

book

Дата: Вторник, 03.08.2021, 14:05 |
Сообщение № 11

Группа: Проверенные

Ранг: Форумчанин

Сообщений: 146


Репутация:

8

±

Замечаний:
0% ±


Excel 2016

PS В реальных данных, оказалось, всегда есть пустые строки, в которых в «контрольном» столбце «0». Таким образом, ситуация, когда только «1» практически исключается. Но все равно еще раз спасибо. Информация (учеба) была полезной и даром не пропадет.



С уважением,
Андрей.

 

Ответить

Понравилась статья? Поделить с друзьями:
  • Excel это формат или расширение
  • Excel это формат или нет
  • Excel это усовершенствованный калькулятор
  • Excel это текстовый редактор или текстовый процессор
  • Excel это текстовый процессор или нет