Страницы: 1 2 След.
RSS
Некорректный результат при работе с базой данных
 
Здравствуйте!!!

Есть проблема и надеюсь найти решение!
Есть Excel с запросом к базе Acssess. Запрос работает, но результат его не соответствует действительности.
Почему? Может я не так кавычки расставил?

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

Скрытый текст
Если есть возможность - скажите что я делал в своём запросе не так?
Спокойствие - величайшее проявление силы.
 
Цитата
Werty пишет: что я делал в своём запросе не так?
запрос ваш не так, с базами тоже работаю не первый год, но что вы хотели сделать так и не понял, пока вы не выложили нормальный запрос,
раз пошла такая пьянка ... вот вам еще решение
Код
 
Query = _
    " SELECT ПЕРВАЯ.ID, ПЕРВАЯ.NAME, ПЕРВАЯ.SITY, ПЕРВАЯ.OLD, ПЕРВАЯ.УК, " & _
    " (   SELECT COUNT(*) " & _
    "    FROM ВТОРАЯ " & _
    "    WHERE ВТОРАЯ.Name = ПЕРВАЯ.Name  " & _
    "        AND ВТОРАЯ.SITY = ПЕРВАЯ.SITY " & _
    "        AND ВТОРАЯ.ID = ПЕРВАЯ.ID " & _
    "        AND ВТОРАЯ.OLD = ПЕРВАЯ.OLD ) AS ПРОВЕРКА " & _
    " FROM ПЕРВАЯ " & _
    " WHERE ПЕРВАЯ.ID = 15000 "
    
 
У вас ID дублируются.
По нормализации БД, если ID это ключевое поле, то оно должно быть уникальным. А у вас из 3 записи с одним ID и разными остальными полями.

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


Наверное вы хотите узнать, сколько записей (строк) в таблице2 у данного пользователя из таблицы1?
1) Сделайте отдельно таблицу с пользователями, и у каждого пользователя должен быть свой уникальный номер, пользователи не должны дублироваться.
2) Эти ЙД пользователей вы должны использовать в таблицах, тогда вы сможете по номеру ЙД связать эти две таблицы без ошибок.
Изменено: Marchuk - 02.07.2014 15:24:25
 
Вот тоже не пойму, как результат запроса может быть неверным? Что просите - то и получаете.
Это как с ВПР() - сколько раз кричали "ВПР() работает неправильно!" и всегда виноват тот, кто "пишет" эту ВПР() - то параметры не так вводят, то не учитывают тип данных...
 
Цитата
Marchuk пишет:
1) Из вашего описания, не ясно в чем ваша проблема.
2) не понятно что вы хотите сделать и что хотите получить в итоге. Поэтому сложно предложить какое либо решение.
У меня огромные массивы данных на работе (более 1 млн. строк). Я их сначала проверял средствами Excel: и циклом с автофильтром и массивом. Но это долго очень. Решил попробовать сделать это с помощью баз данных. Под рукой Acssess - вот с ним и сцепился.
У меня в таблицах ID - только имя столба, а ключом служит отдельных столбик (я эти таблицы просто не планировал связывать между собой по ключу).

Вот такая вот пьянка :)
Спокойствие - величайшее проявление силы.
 
Scripter, работает - я COUNT использовал для подсчёта полей, а не всех значений ...
сейчас проверю что быстрей будет работать.

ПС: спасибо!
Спокойствие - величайшее проявление силы.
 
Цитата
Werty пишет:
Я их сначала проверял средствами Excel: и циклом с автофильтром и массивом. Но это долго очень.
))) вы что в итоге получить хотите? пока все равно не понимаю.
Если удалить дубли, то можно через DISTINCT.
И кстати, Excel умеет работать с листами как будто с таблицами, средствами запросов SQL.

Пример.
Лист1 - лист с данными, первая строка это имена столбцов
Лист2 - лист с данными, первая строка это имена столбцов
Итог - лист с итогом после обработки запроса

Код
Sub Run_Macro()
Dim strSQL As String

    strSQL = "SELECT [Лист1$].*, [Лист2$].* FROM [Лист1$], [Лист2$];"
    
    GenerateReportSQL (strSQL)

    
MsgBox "йа закончило!"
End Sub 

Private Sub GenerateReportSQL(strSQL As String)
Dim ws As Worksheet
Dim qry As QueryTable
Dim strPath As String
Dim strName As String
Dim strCon As String
'Dim strSQL As String
Dim strPosition As String
Dim strRng As String
Dim tm As Double

    With ThisWorkbook
        On Error Resume Next
        Set ws = .Worksheets("Итог")
        On Error GoTo 0
        If ws Is Nothing Then Set ws = .Worksheets.Add(after:=.Worksheets(.Worksheets.Count))
        
        strName = .FullName
        strPath = .Path
        strRng = "A2:U"
        strCon = "ODBC;DSN=Excel Files;" & _
                 "DBQ=" & strName & ";" & _
                 "DefaultDir=" & strPath & ";" & _
                 "DriverId=1046;" & _
                 "MaxBufferSize=2048;" & _
                 "Page Timeout=5;"
        
    
        With ws
            If Val(Application.Version) > 11 Then DeleteConnections_12
            .Cells.Clear
            .Name = "Итог"
            Set qry = .QueryTables.Add(strCon, .Range("A1"), strSQL)
            With qry
                .BackgroundQuery = False
                .Refresh
                .Delete
            End With
        End With
        
    End With

End Sub

Private Sub DeleteConnections_12()
' This line won't work and wouldn't be necessary
' in the versions older than 2007
'*****************************************************************************
    On Error Resume Next: ThisWorkbook.Connections(1).Delete: On Error GoTo 0
    '*****************************************************************************
End Sub



 
Изменено: Marchuk - 02.07.2014 15:34:19
 
Цитата
Marchuk пишет: И кстати, Excel умеет работать с листами как будто с таблицами, средствами запросов SQL.
Т.е. обработка будет такой же быстрой как в базе данных?
Спокойствие - величайшее проявление силы.
 
не знаю, не пробовал 1млн записей ))))
я использую для умножения таблиц, до 50 000 работало быстро.
так удобнее по быстрому, чем создавать таблицы в Access, затем импортировать данные из Excel в БД, потом делать запрос, потом экпортировать обратно в Excel.
 
Цитата
Marchuk пишет: так удобнее по быстрому, чем создавать таблицы в Access, затем импортировать данные из Excel в БД, потом делать запрос, потом экпортировать обратно в Excel.
вот мне именно это нужно!!!!
Пробую Ваш макрос тоже.
Может подскажете, где можно почитать про этот способ работы?
Спокойствие - величайшее проявление силы.
 
Цитата
Werty пишет: Может подскажете, где можно почитать про этот способ работы?
Почитать не помню )))) сам нарыл случайно давно уж.
Вот вам файл с вашим примером. Думаю разберетесь.
 
Всёж думаю макросом без SQL было бы быстрее. Другое дело что код побольше.
 
У автора был SQL запрос, поэтому я это и предложил )))
 
Hugo, макросом быстрее:
циклом с использованием автофильтрма для уменьшения просматриваемого диапазона - 10 записей в сек;
Массивом - тут уже по всему объёму ищется - 1 запись в 3 сек.
С базой данных вообще не получилось.

Макросом Marchuk интересно, но долго опять  :(  

Ну что за невезенье   :oops:
Спокойствие - величайшее проявление силы.
 
Это скорее комментарий к #6

Но если посмотреть на GenerateReportSQL - то тоже код не маленький и не простой...
Изменено: Hugo - 02.07.2014 16:37:00
 
Werty, - нужно иначе макрос писать, без всяких фильтров. Массивы и словарь, как всегда. Пока некогда показать, может чуть позже....
Изменено: Hugo - 02.07.2014 16:39:24
 
Цитата
Werty пишет:
но долго опять
Ну что за невезенье
1) опять таки, так и не понял конечную вашу цель ))
2) Access как раз рассчитан на обработку больших объемов информации.
3) После нехватки скорости обработки Access мы перешли на SQL Server ))))
Изменено: Marchuk - 02.07.2014 16:40:43
 
Конечная цель - обработать данные быстро. С Access не вышло. А использование SQL Server - я до этого ещё не дошёл. А можно? Если Вы знаете, скажите где почитать, плиииииз  :)
Спокойствие - величайшее проявление силы.
 
Цитата
Werty пишет: Макросом Marchuk интересно, но долго опять
Я прошу прощения - всё работает ОООООчень шустро! Я просто не осознал сначала.
Сегодня Вы точно сделали доброе дело - спасибо!!!

 ;)
Спокойствие - величайшее проявление силы.
 
Цитата
Werty пишет: Сегодня Вы точно сделали доброе дело - спасибо!!!
Да не за что )) Главное, что вам помогло в работе.
 
Я не вполне понял что делает запрос - но вот такой макрос делает похожее в 10 раз быстрее.
Для чистоты сравнения добавил аналогичный макрос вывода результата (мерил на примерно по 10000 строк на каждом листе - 0,3 сек):

Код
Sub tt()
    Dim a(), i&
    Dim tm As Single: tm = Timer

    With CreateObject("Scripting.Dictionary"): .comparemode = 1

        a = [ПЕРВАЯ!A1].CurrentRegion.Value
        For i = 2 To UBound(a)
            If a(i, 1) = 15000 Then
                t = a(i, 1) & "|" & a(i, 2) & "|" & a(i, 3) & "|" & a(i, 4) & "|" & a(i, 5)
                .Item(t) = .Item(t) + 1
            End If
        Next

        a = [ВТОРАЯ!A1].CurrentRegion.Value
        For i = 2 To UBound(a)
            If a(i, 1) = 15000 Then
                t = a(i, 1) & "|" & a(i, 2) & "|" & a(i, 3) & "|" & a(i, 4) & "|" & a(i, 5)
                .Item(t) = .Item(t) + 1
            End If
        Next

        ReDim a(1 To .Count + 1, 1 To 6): i = 1
        a(i, 1) = "ID": a(i, 2) = "NAME": a(i, 3) = "SITY": a(i, 4) = "OLD": a(i, 5) = "УК": a(i, 6) = "ПРОВЕРКА"
        For Each k In .keys
            i = i + 1
            arr = Split(k, "|")
            a(i, 1) = arr(0): a(i, 2) = arr(1): a(i, 3) = arr(2): a(i, 4) = arr(3): a(i, 5) = arr(4)
            a(i, 6) = .Item(k)
        Next

    End With

    Generatesh a

    MsgBox "Запрос выполнен! " & Timer - tm
End Sub


Private Sub Generatesh(arr)
Dim ws As Worksheet
 With ThisWorkbook
        On Error Resume Next
        Set ws = .Worksheets("Итог")
        On Error GoTo 0
        If ws Is Nothing Then Set ws = .Worksheets.Add(after:=.Worksheets(.Worksheets.Count))
        With ws
            .Cells.Clear
            .Name = "Итог"
            .[a1].Resize(UBound(arr), UBound(arr, 2)) = arr
        End With
    End With
End Sub


 
Изменено: Hugo - 02.07.2014 17:46:56
 
Hugo, нужно разобраться как работает Ваш макрос (в Вашем примере нужно каждый раз указывать номер - значит нужно каждое значение будет обрабатывать и будет ли это быстрее для всей таблицы - не знаю).
В итоге сегодня получил бОльшую порцию материала для обучения.
Спасибо всем, буду разбираться дальше.
Тему можно закрыть.
Спокойствие - величайшее проявление силы.
 
Я делал как в запросе - там ведь тоже отбор только =15000. Можно собирать словарь всех номеров, без проблем. Ну будет чуть дольше работать...
Поставил четыре апострофа - отобрало всё за полторы секунды (из 2*10000 строк)
Изменено: Hugo - 02.07.2014 18:34:22
 
Цитата
Werty пишет: Т.е. обработка будет такой же быстрой как в базе данных?
нет, конечно.
фрилансер Excel, VBA - контакты в профиле
"Совершенствоваться не обязательно. Выживание — дело добровольное." Э.Деминг
 
Цитата
Hugo пишет: Для чистоты сравнения добавил аналогичный макрос вывода результата (мерил на примерно по 10000 строк на каждом листе - 0,3 сек):
Здравствуйте!
Не могу понять, зачем прибавлять единицу к значению ключа? Если этого не делать то не подсчитывается количество повторений ключа.
Спокойствие - величайшее проявление силы.
 
Единица прибавляется не к значению ключа - а к значению item'а ключа.
Ну и как Вы правильно заметили - если этого не делать то не подсчитывается количество повторений ключа.
А вообще как я уже сказал - я не понял что именно Вы хотели сделать. Может нужно было что-то другое - кто знает...
 
Цитата
Hugo пишет: Единица прибавляется не к значению ключа - а к значению item'а ключа.
Вот я не понимаю :) как можно так сделать: к значению 16000|Петров|Москва|25|5 прибавить 1?
Цитата
Hugo пишет: А вообще как я уже сказал - я не понял что именно Вы хотели сделать. Может нужно было что-то другое - кто знает...
Две таблицы есть у нас: ПЕРВАЯ, ВТОРАЯ.
Проверить нужно во ВТОРОЙ наличие данных из ПЕРВОЙ: что-то на подобие составного ключа, если бы мы проверяли функцией ВПР.
Вот мой вариант того, что нужно на Вашем примере: там где 1 будет в столбике ПРОВЕРКА, значит значение уникально.

Скрытый текст

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

Спасибо.
Изменено: Werty - 04.07.2014 01:59:49
Спокойствие - величайшее проявление силы.
 
Ну сделайте так:

Код
    For i = 2 To UBound(a)
        cou = cou + 1    'что за cou? зачем? что считает? есть ведь i!
        t = a(i, 1) & "|" & a(i, 2) & "|" & a(i, 3) & "|" & a(i, 4) & "|" & a(i, 5)
        Debug.Print .Item(t)
        .Item(t) = .Item(t) + 1
        Debug.Print .Item(t)
    Next 
 
Cou для получения массива такого же размнра что и первая таблица.
С debug я смотрел - я суть не пойму этого сложения текста с цифрой. :(
Спокойствие - величайшее проявление силы.
Страницы: 1 2 След.
Наверх