Решение задачи создания в запросе нумерации вида: 1.1 ----- 1.2 ----- 2.1 ----- и т.д.
Автор: Юрий Шерман www.tour-soft.com Многоуровневая нумерация строк запроса. Статья написана как ответ на вопрос на форуме. Она развивает метод, изложенный в "Нумерации строк запроса". Постановка задачи 1. Пусть имеется запрос (таблица) MyQuery с полями Field_1, ..., Field_n. В запросе могут быть другие поля, кроме типа OLE. Значения полей Field_1, ..., Field_n служат основой многоуровневой нумерации. Предполагается, что группы этих полей различны в различных записях. Предположение. В основных полях нет значений Null. Требуется построить запрос, добавляющий вычисляемые поля Lev_1, ..., Lev_n, нумерующие записи в соответствии со значениями полей Field_1, ..., Field_n, начиная с 1. Решение. Решение дается двумя запросами. Первый запрос MyGroup проводит группировку исходного запроса по основным полям. Поля типа MEMO должны преобразованы в тип String функцией Mid(Field_MEMO,1). Текст запроса MyGroup для трех основных полей: SELECT Field_1, Field_2, Field_3 FROM MyQuery GROUP BY Field_1, Field_2, Field_3; Второй запрос производит собственно многоуровневую нумерацию: SELECT DISTINCT MultiNum(1,Field_1) AS Lev_1, MultiNum(2,Field_2) AS Lev_2, MultiNum(3,Field_3) AS Lev_3, Field_1, Field_2, Field_3 FROM MyGroup WHERE MultiNum(3)=0 ORDER BY Field_1, Field_2, Field_3; В запросе используется функция MultiNum. Вот ее описание: Public Function MultiNum(Lev As Long, Optional Var) As Long Static Num() As Long, VarOld(), i As Long If IsMissing(Var) Then ReDim Num(Lev), VarOld(Lev) Else If VarOld(Lev) <> Var Then VarOld(Lev) = Var Num(Lev) = Num(Lev) + 1 For i = Lev + 1 To UBound(Num) Num(i) = 0 VarOld(i) = Empty Next i End If End If MultiNum = Num(Lev) End Function Комментарий. Количество уровней нумерации задается при обращении к MultiNum в предложении WHERE. Это обращение выполняется только один раз и служит для задания начальных установок функции. Порядок записи вычислений Lev_n в предложении SELECT изменять нельзя. Постановка задачи 2. Отличается от задачи 1 снятием предположения об отсутствии в основных полях значений Null. Решение. Решение дается теми же двумя запросами. Но функцию MultiNum следует заменить на более сложную функцию MultiNumNull: Public Function MultiNumNull(Lev As Long, Optional Var) As Long Static Num() As Long, VarOld(), i As Long If IsMissing(Var) Then ReDim Num(Lev), VarOld(Lev) Else If IsNull(VarOld(Lev)) And IsNull(Var) Then ElseIf IsNull(VarOld(Lev)) Or IsNull(Var) Then GoTo NoEq Else If VarOld(Lev) <> Var Then NoEq: VarOld(Lev) = Var Num(Lev) = Num(Lev) + 1 For i = Lev + 1 To UBound(Num) Num(i) = 0 VarOld(i) = Empty Next i End If End If End If MultiNumNull = Num(Lev) End Function Иногда требуется получить не отдельные нумерующие поля, а текстовую строку вида: "2.1.4", в которой объединены отдельные нумерующие поля. Конечно, это можно сделать третьим запросом. Но решение достигается проще применением другой функции, к тому же не требующей явного указания количества уровней нумерации. Постановка задачи 3. Предположения об исходном запросе такие же, как и в задаче 1. Требуется построить запрос, добавляющий вычисляемое текстовое поле Lev, нумерующее записи в соответствии со значениями полей Field_1, ..., Field_n, начиная с 1. Решение. Решение дается также двумя запросами. Первый запрос совпадает с запросом MyGroup из задачи 1. Второй запрос имеет вид: SELECT DISTINCT MultiLev(Field_1,Field_2,Field_3) AS Lev, Field_1, Field_2, Field_3 FROM QGroup WHERE MultiLev()="" ORDER BY Field_1, Field_2, Field_3; В запросе используется функция MultiLev. Ее описание: Public Function MultiLev(ParamArray P()) As String Static Num() As Long, VarOld(), n As Long, i As Long If UBound(P) = -1 Then ReDim Num(0) Exit Function Else If Num(0) = 0 Then n = UBound(P) ReDim Num(n), VarOld(n) End If For i = 0 To n If VarOld(i) <> P(i) Then Exit For Next i VarOld(i) = P(i) Num(i) = Num(i) + 1 For i = i + 1 To n Num(i) = 1 VarOld(i) = P(i) Next i End If For i = 0 To n MultiLev = MultiLev & "." & Num(i) Next i MultiLev = Mid(MultiLev, 2) End Function Постановка задачи 4. Отличается от задачи 3 снятием предположения об отсутствии в основных полях значений Null. Решение. Решение дается теми же двумя запросами. Но функцию MultiLev следует заменить на более сложную функцию MultiLevNull: Public Function MultiLevNull(ParamArray P()) As String Static Num() As Long, VarOld(), n As Long, i As Long If UBound(P) = -1 Then ReDim Num(0) Exit Function Else If Num(0) = 0 Then n = UBound(P) ReDim Num(n), VarOld(n) End If For i = 0 To n If IsNull(VarOld(i)) And IsNull(P(i)) Then ElseIf IsNull(VarOld(i)) Or IsNull(P(i)) Then GoTo NoEq Else If VarOld(i) <> P(i) Then NoEq: Exit For End If End If Next i VarOld(i) = P(i) Num(i) = Num(i) + 1 For i = i + 1 To n Num(i) = 1 VarOld(i) = P(i) Next i End If For i = 0 To n MultiLevNull = MultiLevNull & "." & Num(i) Next i MultiLevNull = Mid(MultiLevNull, 2) End Function Послесловие. Во всех постановках предполагается отсутствие в исходном запросе полей типа OLE. Однако и при наличии таких полей можно построить нумерацию с помощью групповых запросов, не используя предикат DISTINCT. Но и запросы, и нумерующие функции будут значительно сложнее. Подход к такому построению дан в решении для общего случая в статье "Нумерация строк запроса", указанной выше. Просмотров: 8914
Ваш коментарий будет первым | | |