Смекни!
smekni.com

Cache': техника группировки (стр. 2 из 2)

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

Рассмотрим другое деление группировки - на нормальную и широкую. Проблемой, породившей такое деление, является ограниченность длины индекса. В нашем случае это существенно, поскольку в индексные значения пишутся значения полей. Каким бы ни было магическое число этого ограничения, в целях эффективности реализации СУБД в каждой реализации оно есть. В отдельных реализациях размер индекса совпадает с величиной группировки, в других это две разные величины, но в любом случае предполагаются ограничения на максимальную величину индекса и группирующих полей. Вообще говоря, в большинстве случаев несложного применения и несложного анализа двух вышеприведенных способов группирования вполне хватает. Поэтому оба они называются нормальной группировкой, поскольку в обоих случаях слева от символа равенства стоят именно значения группирующих полей.

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

В этой ситуации помогает условная замена значений полей на соответствующие этим значениям числовые идентификаторы. Скажем, цвету красный сопоставляется число 1, цвету синий - 2 и так далее, после чего в группировании принимают участие не длинные поля типа названия организации, а короткие числа.

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

WideGroup()

k group,map

n i,color,figure,count

s i=""

f s i=$O(^group(i)) q:i="" d

. s color=$p(^group(i),"~",1)

. s figure=$p(^group(i),"~",2)

. ; save colors and figures into special lists

. s map("color",color)=""

. s map("figure",figure)=""

После этого в локальной переменной map содержатся два списка с цветами и фигурами. Отметим, что до полного прохода по результатам выборки данных, попавших на группировку (в нашем случае это O(^group(i))) мы просто не можем построить сортированного списка числовых идентификаторов значений, поскольку данные приходят в заведомо несортированном виде.

После получения списков значений группирующих полей можем построить отображение на соответствующие числовые значения:

s color=""

f s color=$O(map("color",color)) q:color="" d

. ; map color to ordered number

. s map("color",color)=$I(map("color"))

. ; map ordered number to color

. s map("Ncolor",map("color",color))=color

s figure=""

f s figure=$O(map("figure",figure)) q:figure="" d

. ; map figure to ordered number

. s map("figure",figure)=$I(map("figure"))

. ; map ordered number to figure

. s map("Nfigure",map("figure",figure))=figure

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

n ncolor,nfigure

s i=""

f s i=$O(^group(i)) q:i="" d

. s color=$p(^group(i),"~",1)

. s figure=$p(^group(i),"~",2)

. s ncolor=map("color",color)

. s nfigure=map("figure",figure)

. s count=$p(^group(i),"~",3)

. s group(ncolor,nfigure)=count+$G(group(ncolor,nfigure),0)

q

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

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

WriteWideGrouped()

d WideGroup()

n color,ncolor,figure,nfigure,count,cf

s cf="group"

f s cf=$Q(@cf) q:cf="" d

. s ncolor=$qs(cf,1)

. s nfigure=$qs(cf,2)

. s count=@cf

. s color=map("Ncolor",ncolor)

. s figure=map("Nfigure",nfigure)

. w color,?15,figure,?30,count,!

q

Сложно говорить о группировке и не затронуть группировку с подытогами. Например, получение той же группировки, но в которую вставлены данные отдельно по цветам безотносительно фигур игрушек, а также общая величина. Ничего сложного в этом нет. Конечно же, следует использовать тот же механизм группирования, но для каждой строки писать суммирование не только со строкой, идентифицируемой группой полей, но и идентифицируемой специальным маркером подитога вместо группирующего поля. Например, выбрав в качестве маркера подитога символ $C(11), получим группирование с подытогами по цвету:

; group to use $QUERY function

; use SUM function

k group

n i,color,figure,count

s i=""

f s i=$o(^group(i)) q:i="" d

. s color=$p(^group(i),"~",1)

. s figure=$p(^group(i),"~",2)

. s count=$p(^group(i),"~",3)

. s group(color,figure)=count+$G(group(color,figure),0)

. s group(color,$C(11))=count+$G(group(color,$C(11)),0)

q

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