стрілка вверх

Що таке результуюча вибірка та асоціативний масив в теорії Баз Даних?

До створення статті про асоціативний масив мене підштовхнули функції php: fetch_assoc, fetch_array, fetch_row та інший фетч :) Fetch - з англійського отримувати, діставати, що ж до assoc, то напевно ж це буде associative, він же асоціативний.

Що ж, маю бажання визначитись, що таке асоціативний масив даних при роботі із базами даних, та як з ним працювати?

березень 2016

Загальна інформація

Частина 1. Основи.

Розглянемо деякі загальні основи обміну даними між php-скриптом та сервером Бази Даних.

Не буду конкретизувати, що саме виводить скрипт на веб-сторінку, а також яким чином впорядковані дані в таблиці Бази Даних та що це взагалі за дані, без різниці, ціль дістати дані із серверу Бази Даних та перетворити в php-скриптові в зрозумілі сутності, щоб знати, що саме ми виводимо на веб-сторінку.


Розглянемо тестовий php-скрипт на зразок:

<?php

/*створюємо обєкт $db звязку з сервером БД*/
$db = new mysqli ("host", "user""pass""DB");

/*SQL-запит SELECT вибірки даних із таблиці БД*/
$query= "SELECT * FROM City LIMIT 10";

/*Результуюча вибірка даних $result*/
$result  $db->query($query);

/* Виконуємо наобхідні операції з отриманими даними*/
/* Отримуємо асоціативний масив */
while ($row $result->fetch_assoc()) {
   
printf ("%s (%s)\n"$row["Name"], $row["Country"]);
};

/* Очищуємо результуючу вибірку даних */
$result->free_result();

/*закриваємо зєднання із сервером БД*/
$db->close();
?>

Код php-скрипту написаний в обєктно-орієнтовному стилі, хоча нічого не заважає реалізувати скрипт в процедурному ситилі чи навіть в PDO (PHP Data Objects).

Обєктно-орієнтовний стиль програмування зручний тим, що дозволяє створювати та працювати з обєктами.

Якщо мову вести за php, то для роботи з Базами Даних є декілька класів, що дозволяють створювати обєкти, наприклад, клас mysqli чи клас mysqli_result.

В обєктно-орієнтовному програмуванні над обєктом можна виконати такі операції, що мають назву метод класу ( клас mysqli: query(), commit(), close(), set_charset() чи клас mysqli_result: fetch_assoc(), fetch_array(), free()) або застосувати властивість класу ( наприклад, для класу mysqli_result: num_rows, current_field).

Дещо детальніше про обєкти, класи та властивості в навчальній статті об'єктно-орієнтовний стиль програмування.

Обмін даними між веб-сервером та сервером Бази Даних можна представити у вигляді схемки рис.1.


результуюча вибірка даних

Рис.1. Обмін даними між php-скриптом та сервером Бази Даних.

Тобто в реляційній БД наші дані впорядковані зручним способом в таблиці, та керуються відповідною системою керування БД. Щоб опрацювати дані в php-скриптові їх необхідно дістати із серверу БД. Тобто виконати відповідний SQL-запит та отримати результуючу вибірку даних згідно виразу SQL-запиту.

Результуюча вибірка даних із таблиці повертає дані SQL-запиту SELECT.

Взагалі-то рис.1. можна було б дещо скорегувати і включити ще один функціональний суттєвий блок - система керування базою даних (СКБД). Тобто SQL-запит, що був відправлений php-скриптом, обробляється спочатку СКБД. СКБД перевіряє коректність SQL-запиту та виконує впорядкування даних в таблиці згідно запиту. Саме СКБД відповідальна за дані, що в її володіннях.


веб-сервер, система керування базою даних, дані

Рис.2. СКБД в ланцюжку обміну даними між веб-сервером та сервером БД.

Вибір даних із серверу БД може бути будь-яким, це власне за потребою php-скрипту чи власне відповідно до призначення скрипту.

SQL-запит може вибирати якесь одне значення з таблиці, якусь одну колонку (атрибут ) даних, цілий рядок (кортеж) або навіть всі дані таблиці.


вибір даних із таблиці

Рис.3. Варіанти вибору даних із таблиці серверу БД.

Саме тут варто було б і визначитись із асоціативним масивом.

- Що таке асоціативний масив?

Думаю зрозуміло, що масив, - це набір даних, а асоціативний масив - це набір даних відповідно до колонок (атрибутів) таблиці БД.

Детальніше, таблиці даних БД мають відповідні колонки за відповідними іменами.

Наприклад, при створенні таблиці MyGuests маємо колонки: id, firstname, lastname, email, reg_date.

CREATE TABLE MyGuests (
id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(30) NOT NULL,
lastname VARCHAR(30) NOT NULL,
email VARCHAR(50),
reg_date TIMESTAMP
)

Вибірка даних із даної таблиці матиме ассоціативний масив.

Наприклад, один рядок асоціативного масиву: 2, Peter, Brown, his-email@mail.com, 12:20 01-23-2012.

асоціативний масив

Рис.4. Асоціативний масив.

Що ж якщо ми отримали більш-менш орієнтовне уявлення, що таке асоціативний масив, тоді варто розглянути декілька прикладів вибору даних із таблиці, та ознайомитись із деякими із fetch-ів...



Частина 2. Вибір асоціативного масиву із таблиць БД.

Результуюча вибірка даних із таблиці серверу даних повертається у вигляді асоціативного масиву.

Ми можемо отримати дані як:
- fetch_assoc(), дістає асоціативний рядок даних,
- fetch_array(), дістає ряд даних як асоціативний масив, можливий варіант числового індексу масиву даних, або навіть розглядається можливість застосування обох варіантів - асоціативного та числового.
- fetch_all(), дістає всі рядки асоціативного масиву даних,
- fetch_object(), повертає поточний асоціативний рядок даних як обєкт.

Розглянемо кожен із fetch-ів по-черзі.

Для тесту розглянемо простеньку таблицю на зразок "My_Test".

idNameprofessionage
1SashaOperator28
2KolyaOperator24
3OlyaSecretary25
4MaxStudent19

2.1. Метод fetch_assoc()

fetch_assoc() - дістає асоціативний рядок даних.

Розглянемо приклад:

<?php
$db = new mysqli ("host", "user""pass""DB");
$query= "SELECT * FROM My_Test";
$result  $db->query($query);
/*аналіз результуючої вибірки*/
var_dump($result);
while ($row $result->fetch_assoc()) {
   /*виводимо асоціативний рядок*/
   var_dump($row);
};
$result->free_result();

$db->close();
?>

Отримаємо результат:

Результуюча вибірка $result даних з таблиці:

object(mysqli_result)#2 (5) { ["current_field"]=> int(0) ["field_count"]=> int(4) ["lengths"]=> NULL ["num_rows"]=> int(4) ["type"]=> int(0) }

Виводимо асоціативний рядок в циклі

array(4) { ["id"]=> string(1) "1" ["Name"]=> string(5) "Sasha" ["profession"]=> string(8) "Operator" ["age"]=> string(2) "28" } array(4) { ["id"]=> string(1) "2" ["Name"]=> string(5) "Kolya" ["profession"]=> string(8) "Operator" ["age"]=> string(2) "24" } array(4) { ["id"]=> string(1) "3" ["Name"]=> string(4) "Olya" ["profession"]=> string(9) "Secretary" ["age"]=> string(2) "25" } array(4) { ["id"]=> string(1) "4" ["Name"]=> string(3) "Max" ["profession"]=> string(7) "Student" ["age"]=> string(2) "19" }


Як бачимо змінна $row є масив, тому дані асоціативного масиву можна вивести з масиву таким чином:

while ( $row = $results->fetch_assoc()){
   echo $row['id'], $row['Name'] , $row['profession'];
};

Результат роботи скрипту:

1 Sasha Operator
2 Kolya Operator
3 Olya Secretary
4 Max Student

Між іншим, в закромах класу mysqli_result є корисний метод data_seek(), що дозволяє вам встановити, який саме асоціативний рядок вивести.

Наприклад, виведем третій рядок (правда варто памятати, що відлік розпочинається з нуля).

$result  $db->query($query);
$result->data_seek(2);
echo $row['id'], $row['Name'] , $row['profession'];

Результат роботи:

3 Olya Secretary


Якщо дещо розібрались із fetch_assoc(), тоді давайте розглянемо що таке fetch_array()...


2.2. Метод fetch_array()

fetch_array(), дістає ряд даних як асоціативний масив, можливий варіант числового індексу масиву даних, або навіть розглядається можливість застосування обох варіантів - асоціативного та числового.

Якщо брати документацію, то fetch_array() має синтаксис на зразок цього (розгляну стиль ООП):

mixed mysqli_result::fetch_array ([ int $resulttype = MYSQLI_BOTH ] )

де mixed вказує, що метод повертає дані різного типу.

Необовязковий параметр $resulttype вказує в якому форматі повертати асоціативний масив, можна вказати такі варіанти:
- MYSQLI_ASSOC - асоціативний,
- MYSQLI_NUM - числовий,
- MYSQLI_BOTH - обидва попередні варіанти.

В прикладах:

$query "SELECT Name, CountryCode FROM City ORDER by ID LIMIT 3";
$result $mysqli->query($query);

/* Числовий масив */
$row $result->fetch_array(MYSQLI_NUM);
printf ("%s (%s)\n"$row[0], $row[1]);

/* Асоціативний масив */
$row $result->fetch_array(MYSQLI_ASSOC);
printf ("%s (%s)\n"$row["Name"], $row["CountryCode"]);

/* Асоціативний та числовий масив */
$row $result->fetch_array(MYSQLI_BOTH);
printf ("%s (%s)\n"$row[0], $row["CountryCode"]);



Питання 1. - Задав би питання, а якщо не вказувати $resulttype, то в якому форматі вказувати вибір масиву?


<?php
$db = new mysqli ("host", "user""pass""DB");
$query= "SELECT * FROM My_Test";
$result  $db->query($query);

/* Не вказуємо тип */
$row $result->fetch_array();
printf ("%s (%s)\n"$row[0], $row["Name"]);

$result->free_result();

$db->close();
?>

Тоді за замовчуванням, стоїть MYSQLI_BOTH; маємо результат:

1 (Sasha)


Питаннят 2: - А в чому тоді різниця між методами fetch_assoc() та fetch_array()?

Можливо різницю зможемо побачити, якщо проаналізуємо методи за допомогою функції var_dump, реалізуємо тестовий скрипт:

Проаналізуємо третій рядок масиву

<?php
$db = new mysqli ("host", "user""pass""DB");
$query= "SELECT * FROM My_Test";
$result  $db->query($query);

/* Рядок асоціативного масиву fetch_assoc() */
$result->data_seek(2);
$row_01 $result->fetch_assoc();
var_dump($row_01);

/* Той же рядок, але для fetch_array */
$result->data_seek(2);
$row_02 $result->fetch_array();
var_dump($row_02);

$result->free_result();

$db->close();
?>

Тестовий скрипт виведе:

var_dump для fetch_assoc()

array(4) {
  ['id']=>  string(1) '3'
  ['Name']=>  string(5) 'Olya'
  ['profession']=>  string(8) 'Secretary'
  ['age']=>  string(2) '25'
}

var_dump для fetch_array()

array(8) {
  [0]=>  string(1) '3'
  ['id']=>  string(1) '3'
  [1]=> string(5) 'Olya'
  ['Name']=> string(5) 'Olya'
  [2]=> string(8) 'Secretary'
  ['profession']=> string(8) 'Secretary'
  [3]=> string(2) '25'
  ['age']=>  string(2) '25'
}

Маємо відповідь на запитання в чому різниця між двома вибірками: практично ні в чому, єдине масив fetch_array додатково прописаний ще й числами.


2.3. Метод fetch_all()

fetch_all(), дістає всі рядки асоціативного масиву даних.

Синтаксис аналогічний до fetch_array

mixed mysqli_result::fetch_all ([ int $resulttype = MYSQLI_NUM ] )

де mixed вказує, що метод повертає дані різного типу.

Необовязковий параметр $resulttype вказує в якому форматі повертати асоціативний масив, можна вказати такі варіанти:
- MYSQLI_ASSOC - асоціативний,
- MYSQLI_NUM - числовий,
- MYSQLI_BOTH - обидва попередні варіанти.

Скрипт з функцією fetch_all мав би вигляд


<?php
$db = new mysqli ("host", "user""pass""DB");
$query= "SELECT * FROM My_Test";
$result  $db->query($query);

/* Вибираємо всі рядки */
$row $result->fetch_all();
printf ("%s (%s)\n"$row["id"], $row["Name"]);

$result->free_result();
$db->close();
?>

і даний скриптик мав би працювати правильно, проте в мене він видає ось таку от помилку:


Fatal error: Call to undefined method mysqli_result::fetch_all() in ...


Як каже офіційна документаціія функція mysqli_fetch_all() ... (перекладу раптом хтось не знає, функція доступна з бібліотекою mysqlnd).

... Available only with mysqlnd.

Що ж сподіваюсь проблема саме в цьому, проте далі розбиратись чи встановлена в мене бібліотека mysqlnd не буду, зупинюсь на тому що є.



2.4. Метод fetch_object()

fetch_object(), повертає поточний асоціативний рядок даних як обєкт.

Синтаксис функції fetch_object():

object mysqli_result::fetch_object([ string $class_name = "stdClass"[, array $params]] )


Параметри функції:
$class_name - Імя класу, встановлює властивості обєкту. Якщо не вказується, то встановлюється попередньо визначений клас stdClass.
$params - Необовязковий масив параметрів, що передається для конструктору class_name обєкту.

Якщо вже розглядати дану функцію, де рядок представляється як обєкт, і цей обєкт має властивості (атрибути колонок таблиці),- то варто чітко розуміти, що таке взагалі обєкт в програмуванні.

Роботу функції fetch_object() можна розглянути на прикладі, - створимо обєкт із третього рядка тестової таблиці My_Test:

<?php
$db = new mysqli ("host", "user""pass""DB");
$query= "SELECT * FROM My_Test";
$result  $db->query($query);
$result->data_seek(2);
/* Створюємо обєкт із рядка */
$row $result->fetch_object();
echo $obj->id,$obj->Name,$obj->profession;
$result->free_result();
$db->close();
?>

Результат:


3 Olya Secretary




2.5. Метод fetch_row()

Документація php mysqli_fetch_row().

Fetch_row() належить методу класу mysqli_result.

PHP fetch_row() повертає рядок результуючої вибірки даних як числовий масив.

Повертає один рядок даних із результуючої вибірки даних та представляє ці дані у вигляді числового масиву. Масив розпочинається із 0 (нуля). Послідуюче використання функції fetch_row() повертає слідуючу вибірку даних із результуючої вибірки даних, або NULL, якщо рядки закінчились.


Синтаксис

Синтаксис функції fetch_row() обєктно-орієнтовний стиль:

mixed mysqli_result::fetch_row ( void )


Параметри функції:
mixed - функція може повертати різні типи даних,
void - параметри не передаються.

Процедурний стиль:

mixed mysqli_result::fetch_row ( result );

параметр:
result - обов'язковий (процедурний стиль), визначає вибірку результуючих даних, що вказані в mysqli_query(), mysqli_store_result() чи mysqli_use_result().


Функція fetch_row() може бути виконана, як в об'єктно-орієнтовному стилі програмування, так і в процедурному стилі програмування.


Наприклад, застосуємо скрипт в ООП:

<?php
/*створюємо обєкт $db звязку з сервером БД*/
$db = new mysqli ("host", "user""pass""DB");

/*SQL-запит SELECT вибірки даних із таблиці БД*/
$query "SELECT Name, CountryCode FROM City";

if (
$result $db->query($query)) {

    
/* Отримуємо масив */
    
while ($row $result->fetch_row()) {
        
printf ("%s (%s)\n"$row[0], $row[1]);
    }

    
/* Очищуємо результуючу вибірку даних */
    
$result->close();
}

/*закриваємо зєднання із сервером БД*/
$db->close();
?>


Або зразок процедурного стилю:

<?php
/* зєднуємось із БД */
<?php
$db 
mysqli_connect("host""user""pass""db"); $query "SELECT Name, CountryCode FROM City";

if (
$result mysqli_query($db$query)) {

    
/* Дістаємо асоціативний масив */
    
while ($row mysqli_fetch_row($result)) {
        
printf ("%s (%s)\n"$row[0], $row[1]);
    }

    
/* Очищаємо результуючу вибірку даних */
    
mysqli_free_result($result);
}

/* Закриваємо зєднання */
mysqli_close($db);
?>

Приклад застосування функції fetch_row()

<?php
$db = new mysqli ("host", "user""pass""DB");
$query= "SELECT * FROM My_Test";
$result  $db->query($query);

/* Встановлюємо вибір даних із 3 рядка */
$result->data_seek(2);

/* Масив із рядка */
$row $result->fetch_row();
printf ("Id:%s  Name:%s\n"$row[0], $row[1]);

/* Масив із слідуючого рядка */
$row $result->fetch_row();
printf ("Id:%s  Name:%s\n"$row[0], $row[1]);

/* Очищуємо результуючу вибірку даних */
$result->free_result();
$db->close();
?>

Результат роботи скрипту:


Id:2 Name:Kolya
Id:3 Name:Olya


Заключення

Що ж на цьому завершу розгляд матеріалу, і здається fetch_assoc та інші фетчі досить легкі в розумінні варто лиш дещо попрактикуватись :)

- Найкращого в програмуванні!



березень 2016