Эмуляция получения переменного числа столбцов для SQL запроса.

25.07.2011
При работе с СУБД Oracle SQL-запрос с агрегатором LISTAGG позволяет эмулировать получение результата с переменным числом столбцов. В результате мы получаем результат со строго фиксированным числом полей, однако одно поле из набора содержит сериализованную в каком-то виде информацию о переменном числе объектов. После обработки результата простыми средствами PHP мы имеем массив, где каждая из строк может иметь переменное число столбцов.

Эту обработку можно производить на стадии выбора строк из ресурса, который вернулся из запроса к БД (конструкция while( fetch_array ) { … }  или подобная).

Предположим, у нас имеется сохраненная история общения одного человека с другим по нескольким номерам телефонов. Эта история содержит элементы, каждый из которых содержит список некоторого числа возможных пар вида (телефон, результат звонка). Кроме того, в каждом элементе истории имеется поле «время звонка».

Схема данных

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

Пример списка

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

SELECT calls.id, LISTAGG( (phones.phone || ' - ' || call_items.status  ), ' , ')
WITHIN GROUP (ORDER BY phone) AS calls_list FROM calls
LEFT JOIN call_items ON call_items.call_id = calls.id
LEFT JOIN phones ON call_items.PHONE_ID = phones.id
GROUP BY calls.id

С полученным результатом производим манипуляции в следующем ключе:

$query = get( $sql );
while($res = fetch_assoc( $query ) )
{
  $res[‘phones_list’] = explode( ‘,’, $res[‘phones_list’] );
  $list[] = $res;
}

Таким образом, мы получили требуемый список с переменным числом столбцов. Полученный массив легко можно передать в шаблон и без проблем отрисовывать списки с переменным числом столбцов в каждом из элементов.