Форум программистов, компьютерный форум, киберфорум
Microsoft Access
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.88/25: Рейтинг темы: голосов - 25, средняя оценка - 4.88
0 / 0 / 0
Регистрация: 29.03.2013
Сообщений: 20

Сложение данных из символьных полей в запросе с группировкой (аналог функции Sum()

01.06.2013, 14:26. Показов 4978. Ответов 4
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Специально название темы сдублировал с данной статьи
http://am.rusimport.ru/MSAccess/topic.aspx?ID=672

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
Function Наименование(Наряд, Заказ, Номер)
 
Наименование = ""
Запрос = "SELECT Детали.Деталь FROM Наряды, Детали, Работы, Расценка WHERE Наряды.Наряд=Детали.Наряд AND Наряды.Наряд=Работы.Наряд AND Наряды.Заказ=Детали.Заказ AND Наряды.Заказ=Работы.Заказ AND Наряды.Номер=Детали.Номер AND Наряды.Номер=Работы.Номер GROUP BY Наряды.Наряд, Наряды.Заказ, Наряды.Номер, Детали.Тип, Детали.Деталь HAVING Наряды.Наряд=" & Наряд & " AND Наряды.Заказ=""" & Заказ & """ AND Наряды.Номер=" & Номер & " AND Детали.Тип=""Дверь"""
'MsgBox Запрос
Set rs = CurrentDb.OpenRecordset(Запрос)
If Not rs.EOF Then
    Наименование = Наименование + Nz(rs.Fields("Деталь"), 0)
End If
Запрос = "SELECT Детали.Деталь, Детали.[Кол-во] "
Запрос = Запрос & "FROM Наряды, Детали, Работы, Расценка "
Запрос = Запрос & "WHERE Наряды.Наряд=Детали.Наряд And Наряды.Наряд=Работы.Наряд "
Запрос = Запрос & "AND Наряды.Заказ=Детали.Заказ And Наряды.Заказ=Работы.Заказ "
Запрос = Запрос & "AND Наряды.Номер=Детали.Номер And Наряды.Номер=Работы.Номер "
Запрос = Запрос & "GROUP BY Детали.Деталь, Детали.[Кол-во], Наряды.Наряд, Наряды.Заказ, "
Запрос = Запрос & "Наряды.Номер, Детали.Тип, Расценка.Тип, Расценка.КодТип "
Запрос = Запрос & "HAVING Наряды.Наряд=" & Наряд & " AND Наряды.Заказ=""" & Заказ & """ AND Наряды.Номер=" & Номер & " "
Запрос = Запрос & "AND Детали.Тип<>""Дверь"" AND Расценка.Тип=Детали!Тип "
Запрос = Запрос & "ORDER BY Расценка.КодТип"
'MsgBox Запрос
Set rs = CurrentDb.OpenRecordset(Запрос)
If rs.RecordCount > 0 Then
   Do
        Наименование = Наименование & ", "
        Наименование = Наименование & Nz(rs.Fields("Деталь"))
        If rs.Fields("Кол-во") > 1 Then
                Наименование = Наименование & " " & Nz(rs.Fields("Кол-во")) & " шт"
        End If
        rs.MoveNext
        'MsgBox Наименование
   Loop Until rs.EOF
End If
rs.Close
End Function
Проблема в том, что использование подобной функции существенно замедляет работу. На пробной таблице в 10 строк на AMD A10 2800 - считает пару секунд, на нетбуке - секунд 5.
Что будет при нескольких тысячах строк - страшно подумать.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
01.06.2013, 14:26
Ответы с готовыми решениями:

Как в запросе с группировкой получить значение без использования групповых операций по одному из полей?
Приветствую. По причине большого количества строк в таблице excel решил перейти на access, для подготовки данных с последующей...

Редактирование - ввод данных в запросе с группировкой
Может кто знает способ изменения данных в запросе с группировкой? Пока не включаю группировку все ОК.

Соединение строковых, числовых и типа дата полей в запросе. Аналог CAST() SQL
Добрый день! Мне уже объяснили на форуме от 1С, что приведения числовых полей и полей типа дата в строку в запросе 1С НЕВОЗМОЖНО. ...

4
Эксперт MS Access
26826 / 14506 / 3192
Регистрация: 28.04.2012
Сообщений: 15,782
01.06.2013, 14:54
iron-zorin, посмотрите здесь http://hiprog.com/index.php?op... &Itemid=35 - особенно последний метод (по Митину). Думаю будет на порядок быстрее, чем поиск по рекордсету.

Если вдруг, сайт будет закрыт для вас (по непонятным для меня причинам с регистрацией), то я скопирую сюда содержимое страницы.
1
0 / 0 / 0
Регистрация: 29.03.2013
Сообщений: 20
01.06.2013, 16:47  [ТС]
Закрыт
0
Эксперт MS Access
26826 / 14506 / 3192
Регистрация: 28.04.2012
Сообщений: 15,782
01.06.2013, 21:17
В спойлере
Кликните здесь для просмотра всего текста
Слияние полей из разных строк запроса.
Автор Юрий Шерман
16.01.2002 г.
Как соединить данные полей из разных строк запроса в одно поле? Вашему вниманию предлагается оптимальное решение.
Автор: Юрий Шерман
www.tour-soft.com

Слияние полей из разных строк запроса. Новая версия.

Для полей из разных строк запроса в SQL имеется целый ряд групповых функций: Sum, Min, Max и т.д. Однако если Вам надо объединить поля из разных строк, разделяя их, например, запятой, то такой групповой операции Вы не найдете. Придется писать собственное решение.

Постановка задачи.
Пусть у Вас имеется Tab1 (таблица или запрос) с полями: ID и Fam.
ID - групповой номер, он может повторяться, но не пуст (для упрощения).
Fam - поле с фамилией.

Требуется создать запрос TabUnion с двумя полями:
- ID, значения которого взяты из Tab1, но не повторяются;
- FamUnion, которое состоит из списка фамилий через запятую.
Список должен состоять из фамилий с одним ID.

Рассмотрим решение задачи от самого простого случая до самого общего.

Случай 1. Имеются упрощающие предположения.
Предположение 1: Tab1 должна быть таблицей, отсортированной по ID.
Предположение 2: в Tab1 должно быть не менее двух различных значений ID.
Предположение 3: пустых фамилий нет.

Текст запроса TabUnion1:
Select ID, Last(UnionStr1(ID,Fam)) AS FamUnion FROM Tab1
GROUP BY ID;

Описание функции UnionStr1:

Public Function UnionStr1(ID, Fam)
Static IDOld, FamUnion
If IDOld <> ID Then
IDOld = ID
FamUnion = Null
End If

FamUnion = (FamUnion + ", ") & Fam
UnionStr1 = FamUnion
End Function

Оценка скорости: время обработки пропорционально C*n, где C – константа, n – количество записей в Tab1. Очевидно, что оценку улучшить нельзя. То есть метод оптимален.

Случай 2. Отличается от случая 1 снятием предположения 2.
То есть, допускается случай, когда все записи Tab1 имеют один ID.
Тогда приходится заниматься установкой начального значения IDOld.

Текст запроса TabUnion2:
Select ID, Last(UnionStr2(ID,Fam)) AS FamUnion
FROM Tab1
WHERE IsEmpty(UnionStr2())
GROUP BY ID;

Описание функции UnionStr2:

Public Function UnionStr2(Optional ID, Optional Fam)
Static IDOld, FamUnion
If IsMissing(ID) Then
IDOld = Empty
Exit Function
End If
If IDOld <> ID Then
IDOld = ID
FamUnion = Null
End If
FamUnion = (FamUnion + ", ") & Fam
UnionStr2 = FamUnion
End Function

Оценка скорости: такая же, как и в случае 1.
Замечание: чтобы снять предположение о не пустых фамилиях можно (чтобы избежать лишних запятых) использовать в более тяжеловесную конструкцию.
В функциях место строки:
FamUnion = (FamUnion + ", ") & Fam
следует писать:
FamUnion = IIf (IsNull(FamUnion), Fam, FamUnion & (", " + Fam))

Случай 3. Tab1 таблица или запрос. Предположений о сортированности по ID и о пустых фамилиях нет.
Предположение: нет повторяющихся пар: ID, Fam.

В этом случае необходима промежуточная сортировка Tab1 по ID.

Текст промежуточного запроса Tab1Sort для сортировки Tab1:
Select DISTINCT ID, Fam FROM Tab1 ORDER BY ID, Fam;

Текст запроса TabUnion3:
Select ID, Last(UnionStr2(ID,Fam)) AS FamUnion
FROM Tab1Sort
WHERE IsEmpty(UnionStr2())
GROUP BY ID;

Здесь применяется та же функция, что и в случае 2.

Оценка скорости: оценка ухудшается из-за применения сортировки. Известно, что сортировку быстрее, чем C*n*log(n) сделать нельзя. Обычно используют сортировку методом Шелла, которая имеет оценку C*n*log(n)^2. Эта же оценка является оценкой быстродействия в данном случае. Быстрее, очевидно, сделать нельзя.
Замечание: в промежуточной сортировке используется предикат DISTINCT. Он превращает запрос Tab1Sort в статический. Без этого метод неработоспособен. Но этот же предикат удаляет повторяющиеся пары ID, Fam. Поэтому необходимо указанное выше предположение.

Случай 4. Tab1 таблица или запрос. Никаких дополнительных предположений нет.

Для применения метода слияния из случая 3 необходимо все строки Tab1 сделать уникальными.
Для этого используем нумерацию строк запроса, изложенную в статье «Нумерация строк запроса. Новый подход».

Текст промежуточного запроса Tab1Num для нумерации Tab1:
Select DISTINCT Numeration(ID) As Num, ID, Fam
FROM Tab1
WHERE Numeration()=0;

Описание функции Numeration дано в статье, указанной выше.

Текст промежуточного запроса Tab1SortNum для сортировки Tab1Num:
Select DISTINCT ID, Fam, Num FROM Tab1Num ORDER BY ID, Fam;

И, наконец, текст запроса TabUnion4:
Select ID, Last(UnionStr2(ID,Fam)) AS FamUnion
FROM Tab1SortNum
WHERE IsEmpty(UnionStr2())
GROUP BY ID;

Здесь применяется та же функция, что и в случае 2.

Оценка скорости: оценка скорости та же, что и в случае 3, так как нумерация имеет оценку C*n.

Решение поставленной задачи завершено.

Другой вариант постановки задачи.
Предположения о Tab1 остаются прежними.
Теперь требуется заполнить пустую таблицу Tab2, содержащую поля ID и FamUnion значениями, описанными в основной задаче.

Метод 1. Очевидный.
Формируем запрос TabUnion одним из способов, указанных выше.
Затем записываем его результат в Tab2.

Метод 2. Заполнение таблицы Tab2 с помощью Recordset.
Это можно сделать с помощью следующей функции:

Public Function UnionStr3()
Dim R As Recordset, W As Recordset
Dim IDOld, FamUnion

Set R = CurrentDb.OpenRecordset("SELECT * FROM Tab1 ORDER BY ID,Fam")
If R.EOF Then Exit Function

Set W = CurrentDb.OpenRecordset("Tab2")

Do
NewID:
IDOld = R!ID
FamUnion = Null

Union:
FamUnion = (FamUnion + ", ") & R!Fam
R.MoveNext

If R.EOF Then GoTo WriteUnion
If IDOld <> R!ID Then

WriteUnion:
W.AddNew
W!ID = IDOld
W!FamUnion = FamUnion
W.Update
Else
GoTo Union
End If
If Not R.EOF Then GoTo NewID
Exit Do
Loop
End Function

Область применения: в том случае, когда кроме составления списка нужно сделать еще какие-нибудь нестандартные операции.
Недостаток: по факту работает значительно медленнее метода 1.


Метод 3. Заполнение таблицы при помощи запросов (по Митину).
Ссылка: http://c85.cemi.rssi.ru/Access... ?QID=14147

Оригинальный и неочевидный метод.
Выполняется с помощью двух запросов.
1. Запись в Tab2 уникальных ID без фамилий.
Текст запроса WriteID:
INSERT INTO Tab2 (ID) Select DISTINCT ID FROM Tab1;

2. Запись списков фамилий.
Текст запроса TabUnion5:
UPDATE Tab2 INNER JOIN Tab1 On Tab2.ID = Tab1.ID
Set Tab2.FamUnion = ([Tab2].[FamUnion]+", ") & [Tab1].[Fam];

Оценка скорости: по-видимому, работает быстрее метода 1 за счет отсутствия вызова специальных функций.
Недостаток: "Однако в T-SQL это непрокатывает" (Митин).


Общий недостаток всех методов: при большом объеме данных все методы заполнения Tab2 работают достаточно долго.
Если результат (список фамилий) используется часто, то лучше Tab2 сделать постоянной таблицей в базе общего доступа. Далее корректировать ее при изменении Tab1. Так как одиночная корректировка Tab1 меняет только один список в Tab2, то при этом объем работы будет мал и выполнится быстро.

Реализация для базы Access: в форме, в которой можно изменить Tab1 следует на события создания/измения/удаления записи молча проводить синхронные изменения в Tab2.

Собственно такую же рекомендацию для MS SQL дает и Митин: "Я в общем то для обеспечения максимальной производительности остановился на решении, когда на триггерах поддерживается перечень упаковок в основной табл. при изменении записей в табл. с упаковками."
1
Эксперт MS Access
 Аватар для alvk
7459 / 4592 / 302
Регистрация: 12.08.2011
Сообщений: 14,380
03.06.2013, 02:27
mobile, Может ссылка не туда? Потому что у меня вот эта и она открывается:
http://hiprog.com/index.php?op... &Itemid=35

Ой блин, не открывается, причём только из этого форума. Баг или фича? Ладно:

hiprog.com/index.php?option=com_content&task=view&i d=334&Itemid=35
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
03.06.2013, 02:27
Помогаю со студенческими работами здесь

В запросе с использованием функции sum в некоторых местах удвоены итоговые значения
Добрый день. Есть вот такая база данных (схема в приложении). Краткая информация о базе данных &quot;Фирма вторсырья&quot;: ...

Фильтрация данных в запросе по значениям полей на форме
помогите решить задачу с фильтрацией данных в запросе по значениям полей на форме что есть - какой то запрос, например qrTest с двумя...

Объединение в запросе с группировкой, вложенный запрос
Доброго времени суток! Что то не так не группирует. Как исправить куда копать? ВЫБРАТЬ ВложенныйЗапрос.Наименование, ...

Перечисление строк через запятую в запросе с группировкой
Добрый день! Необходимо при выводе запроса сгрупировать список по полю ID договора, при этом значения поля Зав № уплотнения...

sum в SQL запросе
имеется такой простой запрос с агрегатной функцией SUM SELECT SUM( Kolchasov ) summa, IDPrepod, IDPredmet, Kolchasov FROM...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru