Часто при роботі з базами даних постає задача перетворення структур вихідних відносин для виконання тієї або інші операції над ними. Однією з таких задач є вибір даних із бази в список для наступної обробки.
У складі Прологу для цих цілей передбачений стандартний предикат findall (знайти_усі). Даний предикат обчислює усі відповіді на запит і повертає їх у вигляді списку. Синтаксис цього предиката має вигляд:
findall (Variable, Predicat_expression, List_name),
де List_name – ім'я змінної списку відповідей на запит, Predicat_expression – запит з змінними, що записаний у вигляді деякого предикатного виразу; Variable – об’єкт предикатного виразу Predicat_expression, що визначає структуру елемента списку List_name.
Для пояснення використання даного предиката для перетворення структур даних у список розглянемо приклад (програма 4.7).
/* програма 4.7 */
domains
number, salary=integer
name=string
list_worker=name*
predicates
work (name, number, salary)
clauses
work („Кардаш”, 101. 500).
work („Денега”, 211,400).
work („Петренко”, 101,300).
work („Маслов”, 101,200).
Маємо базу даних work (), описану відповідним предикатом і задану набором фактів. Оскільки обробка фактів здійснюється завжди в тому порядку, як вони задані в програмі, то можуть виникнути незручності, якщо потрібно буде сортувати, упорядковувати і т.п. прізвища співробітників.
Для цих цілей зручніше використовувати спискові структури організації даних.
Нехай для нашого прикладу потрібно сформувати список прізвищ співробітників визначеного відділу. Для цього потрібно описати структуру цього списку в секції domains і використовувати предикат findall у наступному виді:
findall (Name, work (Name, 101, _), List_Name),
Тут Name є вільною змінною для значень прізвищ, що задовольняють запитові у вигляді предикатного виразу work (Name, 101, _). Крім того, змінна Name визначає, що елементами списку List_Name будуть прізвища. У результаті виконання предикату findall список List_Name буде містити прізвища всіх службовців 101 відділу.
Приведений приклад 4.7 показує, що предикат findall забезпечує фільтрацію, пошук і формування списку даних, що задовольняють умову пошуку в БД. Однак, даний приклад ілюстрував тільки сам процес пошуку і перетворення даних, не зв’язуючи його з процесом обробки.
Розглянемо ще один приклад, який ілюструє той випадок, коли задача обробки даних визначає необхідність перетворення їх структур.
Нехай потрібно на основі бази даних work () знайти загальний фонд зарплати і середню зарплату в кожному з відділів. Програма 4.8 вирішує цю задачу.
/* програма 4.8 */
domains
number,salary=integer
name=string
list_salary=salary*
predicates
work (name,number,salary)
sum_list (list_salary,salary,integer)
show_sum
find_sum (number)
clauses
show_sum:-makewindow (1,7,15, "Зарплата:",5, 10, 12, 30), cursor (2,1), write ("Введіть номер відділу -> "), readint (Otd), find_sum (Оtd), readchar (_).
find_sum (Оtd) :- findall (Many, work (_, Otd, Many), Lmany), sum_list (Lmany, Sum, Member), write (“загальний фонд:”, Sum), nl, write (“службовців: ”, Member), nl, Ave=Sum/Member, write (“середня з/п: ”, Ave), nl.
sum_list ([] ,0,0).
sum_list ([ H|T ], Sum, Num) :- sum_list (T, S, N), Sum=H+S, Num=N+1.
work („Кардаш”, 101. 500).
work („Денега”, 211,400).
work („Петренко”, 101,300).
work („Маслов”, 101,200).
Предикат show_sum дає можливість ввести номер потрібного відділу і забезпечити потрібний розрахунок, звернувшись до предиката find_sum ().
Предикат find_sum () на основі фактів бази work () формує список окладів співробітників відділу – Lmany, обчислює суму елементів списку і їхню кількість, виводить отримані дані разом з обчисленим середнім значенням на екран.
Суму елементів списку знаходить предикат sum_list. Він же підраховує число елементів у списку.
У предикаті sum_list реалізована рекурсивна процедура, аналогічна тій, що була використана при описі процедури пошуку довжини списку.






