Выборка данных с использованием JDatabase

From Joomla! Documentation

This page is a translated version of the page Selecting data using JDatabase and the translation is 25% complete.
Outdated translations are marked like this.
Other languages:
English • ‎Nederlands • ‎español • ‎français • ‎русский • ‎中文(中国大陆)‎ • ‎中文(台灣)‎
Joomla! 
3.x
Joomla! 
2.5
Примечание о версии

Обратите внимание на множество примеров использования онлайн $db->query() вместо $db->execute(). Это был старый метод в Joomla 1.5 и 2.5, и в Joomla 3.0+ он устарел.

Этот урок разделен на две независимые части:

  • Вставка, обновление и удаление данных из базы данных.
  • Выборка данных из одной или нескольких таблиц и извлечение их в различных формах

Этот раздел документации посвящен выборке данных из таблицы базы данных и их получению в различных форматах. Чтобы увидеть другую часть нажмите здесь

Введение

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

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

Запрос

Запросы к базе данных Joomla изменились с введением Joomla 1.6. Рекомендуемый способ построения запросов к базе данных - «цепочка запросов» (хотя строковые запросы все еще поддерживаются).

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

Чтобы получить новый экземпляр класса JDatabaseQuery, мы используем метод getQuery JDatabaseDriver:

$db = JFactory::getDbo();

$query = $db->getQuery(true);

JDatabaseDriver :: getQuery принимает необязательный аргумент $ new, который может иметь значение true или false (по умолчанию используется значение false).

Чтобы запросить наш источник данных, мы можем вызвать несколько методов JDatabaseQuery; эти методы инкапсулируют язык запросов источника данных (в большинстве случаев SQL), скрывая специфический синтаксис запроса от разработчика и увеличивая переносимость исходного кода разработчика.

Некоторые из наиболее часто используемых методов включают в себя; include; select, from, join, where and order. Существуют также такие методы, как вставка, insert, update and delete для изменения записей в хранилище данных. Объединяя эти и другие вызовы методов, вы можете создать практически любой запрос к вашему хранилищу данных без ущерба для переносимости кода..

Выбор записей из одной таблицы

Ниже приведен пример создания запроса к базе данных с использованием класса JDatabaseQuery. Используя методы select, from, where и order, мы можем создавать гибкие, легко читаемые и переносимые запросы:

// Get a db connection.
$db = JFactory::getDbo();

// Create a new query object.
$query = $db->getQuery(true);

// Select all records from the user profile table where key begins with "custom.".
// Order it by the ordering field.
$query->select($db->quoteName(array('user_id', 'profile_key', 'profile_value', 'ordering')));
$query->from($db->quoteName('#__user_profiles'));
$query->where($db->quoteName('profile_key') . ' LIKE ' . $db->quote('custom.%'));
$query->order('ordering ASC');

// Reset the query using our newly populated query object.
$db->setQuery($query);

// Load the results as a list of stdClass objects (see later for more options on retrieving data).
$results = $db->loadObjectList();

(Here the quoteName() function adds appropriate quotes around the column names to avoid conflicts with any database reserved word, now or in the future.)

Запрос также может быть объединен для дальнейшего упрощения:

$query
    ->select($db->quoteName(array('user_id', 'profile_key', 'profile_value', 'ordering')))
    ->from($db->quoteName('#__user_profiles'))
    ->where($db->quoteName('profile_key') . ' LIKE ' . $db->quote('custom.%'))
    ->order('ordering ASC');

Цепочка может стать полезной, когда запросы становятся длиннее и сложнее.

Группировка может быть достигнута очень просто. Следующий запрос будет подсчитывать количество статей в каждой категории.

$query
    ->select(array('catid', 'COUNT(*)'))
    ->from($db->quoteName('#__content'))
    ->group($db->quoteName('catid'));

Ограничение может быть установлено на запрос с помощью «setLimit». Например, в следующем запросе будет возвращено до 10 записей.

$query
    ->select($db->quoteName(array('user_id', 'profile_key', 'profile_value', 'ordering')))
    ->from($db->quoteName('#__user_profiles'))
    ->setLimit('10');


Выбор записей из нескольких таблиц

Используя методы JDatabaseQuery join, мы можем выбирать записи из нескольких связанных таблиц. Общий метод "join" принимает два аргумента; тип соединения (inner, outer, left, right) и условие соединения. В следующем примере вы заметите, что мы можем использовать все ключевые слова, которые мы обычно использовали бы, если бы писали собственный SQL-запрос, включая ключевое слово AS для псевдонимов таблиц и ключевое слово ON для создания связей между таблицами. Также обратите внимание, что псевдоним таблицы используется во всех методах, которые ссылаются на столбцы таблицы (select, where, order).

// Get a db connection.
$db = JFactory::getDbo();

// Create a new query object.
$query = $db->getQuery(true);

// Select all articles for users who have a username which starts with 'a'.
// Order it by the created date.
// Note by putting 'a' as a second parameter will generate `#__content` AS `a`
$query
    ->select(array('a.*', 'b.username', 'b.name'))
    ->from($db->quoteName('#__content', 'a'))
    ->join('INNER', $db->quoteName('#__users', 'b') . ' ON ' . $db->quoteName('a.created_by') . ' = ' . $db->quoteName('b.id'))
    ->where($db->quoteName('b.username') . ' LIKE ' . $db->quote('a%'))
    ->order($db->quoteName('a.created') . ' DESC');

// Reset the query using our newly populated query object.
$db->setQuery($query);

// Load the results as a list of stdClass objects (see later for more options on retrieving data).
$results = $db->loadObjectList();

Вышеуказанный метод соединения позволяет нам запрашивать как таблицу с контентом, так и таблицу с пользователями, получая статьи с указанием их авторов. Есть также удобные методы для соединений:

Мы можем использовать несколько объединений для запроса более чем двух таблиц:

$query
    ->select(array('a.*', 'b.username', 'b.name', 'c.*', 'd.*'))
    ->from($db->quoteName('#__content', 'a'))
    ->join('INNER', $db->quoteName('#__users', 'b') . ' ON ' . $db->quoteName('a.created_by') . ' = ' . $db->quoteName('b.id'))
    ->join('LEFT', $db->quoteName('#__user_profiles', 'c') . ' ON ' . $db->quoteName('b.id') . ' = ' . $db->quoteName('c.user_id'))
    ->join('RIGHT', $db->quoteName('#__categories', 'd') . ' ON ' . $db->quoteName('a.catid') . ' = ' . $db->quoteName('d.id'))
    ->where($db->quoteName('b.username') . ' LIKE ' . $db->quote('a%'))
    ->order($db->quoteName('a.created') . ' DESC');

Обратите внимание, как сцепление делает исходный код намного более читабельным для этих более длинных запросов.

В некоторых случаях вам также потребуется использовать предложение AS при выборе элементов, чтобы избежать конфликтов имен столбцов. В этом случае несколько операторов выбора могут быть объединены в цепочку с использованием второго параметра $ db-> quoteName.

$query
    ->select('a.*')
    ->select($db->quoteName('b.username', 'username'))
    ->select($db->quoteName('b.name', 'name'))
    ->from($db->quoteName('#__content', 'a'))
    ->join('INNER', $db->quoteName('#__users', 'b') . ' ON ' . $db->quoteName('a.created_by') . ' = ' . $db->quoteName('b.id'))
    ->where($db->quoteName('b.username') . ' LIKE ' . $db->quote('a%'))
    ->order($db->quoteName('a.created') . ' DESC');

Второй массив также можно использовать в качестве второго параметра оператора select для заполнения значений предложения AS. Не забудьте включить пустые значения во второй массив, чтобы они соответствовали столбцам в первом массиве, для которого вы не хотите использовать предложение AS:

$query
    ->select(array('a.*'))
    ->select($db->quoteName(array('b.username', 'b.name'), array('username', 'name')))
    ->from($db->quoteName('#__content', 'a'))
    ->join('INNER', $db->quoteName('#__users', 'b') . ' ON ' . $db->quoteName('a.created_by') . ' = ' . $db->quoteName('b.id'))
    ->where($db->quoteName('b.username') . ' LIKE ' . $db->quote('a%'))
    ->order($db->quoteName('a.created') . ' DESC');

Using OR in queries

When using multiple WHERE clauses in your query, they will be treated as an AND.

So, for example, the query below will return results where the 'name' field AND the 'state' field match.

$query = $db
    ->getQuery(true)
    ->select('COUNT(*)')
    ->from($db->quoteName('#__my_table'))
    ->where($db->quoteName('name') . " = " . $db->quote($value)
    ->where($db->quoteName('state') . " = " . $db->quote($state));

To use a WHERE clause as an OR, the query can be written like this

$query = $db
    ->getQuery(true)
    ->select('COUNT(*)')
    ->from($db->quoteName('#__my_table'))
    ->where($db->quoteName('name') . " = " . $db->quote($name_one), 'OR')
    ->where($db->quoteName('name') . " = " . $db->quote($name_two));

it can also be written like this

$query = $db
    ->getQuery(true)
    ->select('COUNT(*)')
    ->from($db->quoteName('#__my_table'))
    ->where($db->quoteName('name') . " = " . $db->quote($name_one)
    ->orWhere($db->quoteName('name') . " = " . $db->quote($name_two));

Результаты запроса

Класс для базы данных содержит много методов для работы с набором результатов запроса.

If there are no matches to the query, the result will be null.

Одно значение результата

loadResult()

Используйте loadResult(), когда вы ожидаете только одно значение от запроса к вашей базе данных.

id name email username
1 John Smith johnsmith@domain.example johnsmith
2 Magda Hellman magda_h@domain.example magdah
3 Yvonne de Gaulle ydg@domain.example ydegaulle

Это часто является результатом запроса 'count' для получения нескольких записей:

$db = JFactory::getDbo();
$query = $db
    ->getQuery(true)
    ->select('COUNT(*)')
    ->from($db->quoteName('#__my_table'))
    ->where($db->quoteName('name') . " = " . $db->quote($value));

// Reset the query using our newly populated query object.
$db->setQuery($query);
$count = $db->loadResult();

или где вы просто ищете одно поле из одной строки таблицы (или, возможно, одно поле из первой строки возвращается).

$db = JFactory::getDbo();
$query = $db
    ->getQuery(true)
    ->select('field_name')
    ->from($db->quoteName('#__my_table'))
    ->where($db->quoteName('some_name') . " = " . $db->quote($some_value));

$db->setQuery($query);
$result = $db->loadResult();

Результаты в одной строке

Each of these results functions will return a single record from the database even though there may be several records that meet the criteria that you have set. To get more records you need to call the function again.

id name email username
1 John Smith johnsmith@domain.example johnsmith
2 Magda Hellman magda_h@domain.example magdah
3 Yvonne de Gaulle ydg@domain.example ydegaulle

loadRow()

loadRow() returns an indexed array from a single record in the table:

. . .
$db->setQuery($query);
$row = $db->loadRow();
print_r($row);

will give:

Array ( [0] => 1, [1] => John Smith, [2] => johnsmith@domain.example, [3] => johnsmith ) 

You can access the individual values by using:

$row['index'] // e.g. $row['2']

Notes:

  1. The array indices are numeric starting from zero.
  2. Whilst you can repeat the call to get further rows, one of the functions that returns multiple rows might be more useful.

loadAssoc()

loadAssoc() returns an associated array from a single record in the table:

. . .
$db->setQuery($query);
$row = $db->loadAssoc();
print_r($row);

will give:

Array ( [id] => 1, [name] => John Smith, [email] => johnsmith@domain.example, [username] => johnsmith )

You can access the individual values by using:

$row['name'] // e.g. $row['email']

Notes:

  1. Whilst you can repeat the call to get further rows, one of the functions that returns multiple rows might be more useful.

loadObject()

loadObject returns a PHP object from a single record in the table:

. . .
$db->setQuery($query);
$result = $db->loadObject();
print_r($result);

will give:

stdClass Object ( [id] => 1, [name] => John Smith, [email] => johnsmith@domain.example, [username] => johnsmith )

You can access the individual values by using:

$result->index // e.g. $result->email

Notes:

  1. Whilst you can repeat the call to get further rows, one of the functions that returns multiple rows might be more useful.

Single Column Results

Each of these results functions will return a single column from the database.

id name email username
1 John Smith johnsmith@domain.example johnsmith
2 Magda Hellman magda_h@domain.example magdah
3 Yvonne de Gaulle ydg@domain.example ydegaulle

loadColumn()

loadColumn() returns an indexed array from a single column in the table:

$query->select('name'));
      ->from . . .";
. . .
$db->setQuery($query);
$column= $db->loadColumn();
print_r($column);

will give:

Array ( [0] => John Smith, [1] => Magda Hellman, [2] => Yvonne de Gaulle )

You can access the individual values by using:

$column['index'] // e.g. $column['2']

Notes:

  1. The array indices are numeric starting from zero.
  2. loadColumn() is equivalent to loadColumn(0).

loadColumn($index)

loadColumn($index) returns an indexed array from a single column in the table:

$query->select(array('name', 'email', 'username'));
      ->from . . .";
. . .
$db->setQuery($query);
$column= $db->loadColumn(1);
print_r($column);

will give:

Array ( [0] => johnsmith@domain.example, [1] => magda_h@domain.example, [2] => ydg@domain.example )

You can access the individual values by using:

$column['index'] // e.g. $column['2']

loadColumn($index) allows you to iterate through a series of columns in the results

. . .
$db->setQuery($query);
for ( $i = 0; $i <= 2; $i++ ) {
  $column= $db->loadColumn($i);
  print_r($column);
}

will give:

Array ( [0] => John Smith, [1] => Magda Hellman, [2] => Yvonne de Gaulle ),
Array ( [0] => johnsmith@domain.example, [1] => magda_h@domain.example, [2] => ydg@domain.example ),
Array ( [0] => johnsmith, [1] => magdah, [2] => ydegaulle )

Notes:

  1. The array indices are numeric starting from zero.

Multi-Row Results

Each of these results functions will return multiple records from the database.

id name email username
1 John Smith johnsmith@domain.example johnsmith
2 Magda Hellman magda_h@domain.example magdah
3 Yvonne de Gaulle ydg@domain.example ydegaulle

loadRowList()

loadRowList() returns an indexed array of indexed arrays from the table records returned by the query:

. . .
$db->setQuery($query);
$row = $db->loadRowList();
print_r($row);

will give (with line breaks added for clarity):

Array ( 
[0] => Array ( [0] => 1, [1] => John Smith, [2] => johnsmith@domain.example, [3] => johnsmith ), 
[1] => Array ( [0] => 2, [1] => Magda Hellman, [2] => magda_h@domain.example, [3] => magdah ), 
[2] => Array ( [0] => 3, [1] => Yvonne de Gaulle, [2] => ydg@domain.example, [3] => ydegaulle ) 
)

You can access the individual rows by using:

$row['index'] // e.g. $row['2']

and you can access the individual values by using:

$row['index']['index'] // e.g. $row['2']['3']

Notes:

  1. The array indices are numeric starting from zero.

loadAssocList()

loadAssocList() returns an indexed array of associated arrays from the table records returned by the query:

. . .
$db->setQuery($query);
$row = $db->loadAssocList();
print_r($row);

will give (with line breaks added for clarity):

Array ( 
[0] => Array ( [id] => 1, [name] => John Smith, [email] => johnsmith@domain.example, [username] => johnsmith ), 
[1] => Array ( [id] => 2, [name] => Magda Hellman, [email] => magda_h@domain.example, [username] => magdah ), 
[2] => Array ( [id] => 3, [name] => Yvonne de Gaulle, [email] => ydg@domain.example, [username] => ydegaulle ) 
) 

You can access the individual rows by using:

$row['index'] // e.g. $row['2']

and you can access the individual values by using:

$row['index']['column_name'] // e.g. $row['2']['email']

loadAssocList($key)

loadAssocList('key') returns an associated array - indexed on 'key' - of associated arrays from the table records returned by the query:

. . .
$db->setQuery($query);
$row = $db->loadAssocList('username');
print_r($row);

will give (with line breaks added for clarity):

Array ( 
[johnsmith] => Array ( [id] => 1, [name] => John Smith, [email] => johnsmith@domain.example, [username] => johnsmith ), 
[magdah] => Array ( [id] => 2, [name] => Magda Hellman, [email] => magda_h@domain.example, [username] => magdah ), 
[ydegaulle] => Array ( [id] => 3, [name] => Yvonne de Gaulle, [email] => ydg@domain.example, [username] => ydegaulle ) 
)

You can access the individual rows by using:

$row['key_value'] // e.g. $row['johnsmith']

and you can access the individual values by using:

$row['key_value']['column_name'] // e.g. $row['johnsmith']['email']

Note: Key must be a valid column name from the table; it does not have to be an Index or a Primary Key. But if it does not have a unique value you may not be able to retrieve results reliably.

loadAssocList($key, $column)

loadAssocList('key', 'column') returns an associative array, indexed on 'key', of values from the column named 'column' returned by the query:

. . .
$db->setQuery($query);
$row = $db->loadAssocList('id', 'username');
print_r($row);

will give (with line breaks added for clarity):

Array ( 
[1] => John Smith, 
[2] => Magda Hellman, 
[3] => Yvonne de Gaulle,
)

Note: Key must be a valid column name from the table; it does not have to be an Index or a Primary Key. But if it does not have a unique value you may not be able to retrieve results reliably.

loadObjectList()

loadObjectList() returns an indexed array of PHP objects from the table records returned by the query:

. . .
$db->setQuery($query);
$row = $db->loadObjectList();
print_r($row);

will give (with line breaks added for clarity):

Array ( 
[0] => stdClass Object ( [id] => 1, [name] => John Smith, 
    [email] => johnsmith@domain.example, [username] => johnsmith ), 
[1] => stdClass Object ( [id] => 2, [name] => Magda Hellman, 
    [email] => magda_h@domain.example, [username] => magdah ), 
[2] => stdClass Object ( [id] => 3, [name] => Yvonne de Gaulle, 
    [email] => ydg@domain.example, [username] => ydegaulle ) 
)

You can access the individual rows by using:

$row['index'] // e.g. $row['2']

and you can access the individual values by using:

$row['index']->name // e.g. $row['2']->email

loadObjectList($key)

loadObjectList('key') returns an associated array - indexed on 'key' - of objects from the table records returned by the query:

. . .
$db->setQuery($query);
$row = $db->loadObjectList('username');
print_r($row);

will give (with line breaks added for clarity):

Array ( 
[johnsmith] => stdClass Object ( [id] => 1, [name] => John Smith, 
    [email] => johnsmith@domain.example, [username] => johnsmith ), 
[magdah] => stdClass Object ( [id] => 2, [name] => Magda Hellman, 
    [email] => magda_h@domain.example, [username] => magdah ), 
[ydegaulle] => stdClass Object ( [id] => 3, [name] => Yvonne de Gaulle, 
    [email] => ydg@domain.example, [username] => ydegaulle ) 
)

You can access the individual rows by using:

$row['key_value'] // e.g. $row['johnsmith']

and you can access the individual values by using:

$row['key_value']->column_name // e.g. $row['johnsmith']->email

Note: Key must be a valid column name from the table; it does not have to be an Index or a Primary Key. But if it does not have a unique value you may not be able to retrieve results reliably.

Miscellaneous Result Set Methods

getNumRows()

getNumRows() will return the number of result rows found by the last SELECT or SHOW query and waiting to be read. To get a result from getNumRows() you have to run it after the query and before you have retrieved any results. To retrieve the number of rows affected by a INSERT, UPDATE, REPLACE or DELETE query, use getAffectedRows().

. . .
$db->setQuery($query);
$db->execute();
$num_rows = $db->getNumRows();
print_r($num_rows);
$result = $db->loadRowList();

will return

3

Note: getNumRows() is only valid for statements like SELECT or SHOW that return an actual result set. If you run getNumRows() after loadRowList() - or any other retrieval method - you will get a PHP Warning:

Warning: mysql_num_rows(): 80 is not a valid MySQL result resource 
in libraries\joomla\database\database\mysql.php on line 344

Sample Module Code

Below is the code for a simple Joomla module which you can install and run to demonstrate use of the JDatabase functionality, and which you can adapt to experiment with some of the concepts described above. If you are unsure about development and installing a Joomla module then following the tutorial at Creating a simple module will help.

Important note: In any Joomla extensions which you develop that you should avoid accessing the core Joomla tables directly like this and should instead use the Joomla APIs if at all possible, because the database structures may change without warning.

In a folder mod_db_select create the following 2 files:

mod_db_select.xml

<?xml version="1.0" encoding="utf-8"?>
<extension type="module" version="3.1" client="site" method="upgrade">
    <name>Database select query demo</name>
    <version>1.0.1</version>
    <description>Code demonstrating use of Joomla Database class to perform SQL SELECT queries</description>
    <files>
        <filename module="mod_db_select">mod_db_select.php</filename>
    </files>
</extension>

mod_db_select.php

<?php
defined('_JEXEC') or die('Restricted Access');

use Joomla\CMS\Factory;

$db = Factory::getDbo();

$me = Factory::getUser();

$query = $db->getQuery(true);

$query->select($db->quoteName(array('name', 'email')))
	->from($db->quoteName('#__users'))
	->where($db->quoteName('id') . ' != ' . $db->quote($me->id))
	->order($db->quoteName('name') . ' ASC');

$db->setQuery($query);

echo $db->replacePrefix((string) $query);

$results = $db->loadAssocList();

foreach ($results as $row) {
	echo "<p>" . $row['name'] . ", " . $row['email'] . "<br></p>";
}

The code above selects and outputs the username and email of the records in the Joomla users table, apart from those of the currently logged-on user. The method Factory::getUser() returns the user object of the currently logged-on user, or if not logged on, then a blank user object, whose id field is set to zero.

The $db->replacePrefix((string) $query) expression returns the actual SQL statement, and outputting this can be useful in debugging.

Zip up the mod_db_select directory to create mod_db_select.zip.

Within your Joomla administrator go to Install Extensions and via the Upload Package File tab select this zip file to install this sample log module.

Make this module visible by editing it (click on it within the Modules page) then:

  1. making its status Published
  2. selecting a position on the page for it to be shown
  3. on the menu assignment tab specify the pages it should appear on

When you visit a site web page then you should see the module in your selected position, and it should output the SQL SELECT statement and the sequence of name, email values from the Joomla users table.

See also