Как показать записи из трех таблиц без foreach

У меня проблема, как сделать запрос для объединения записей из 3 таблиц и вывода результатов на экран. Я принял решение, но не для скорости, и я искал лучшее решение. Мои таблицы:

тестовая таблица

id_test
testName

таблица вопросов

id_quest
id_test
question

таблица ответов

id_answer
id_quest
answer

В каждом тесте есть 7 вопросов, и на каждый вопрос есть 10 ответов.

Как написать запрос к базе данных без foreach, чтобы отобразить эти записи на экране?

Я сделал такое решение:

    $this->db->select('id_test,testName,description,time,type,sum');
    $this->db->where('id_test',$idTest);
    $query['test'] = $this->db->get('tests')->result()[0];

    $this->db->select('id_quest,inquiry');
    $this->db->where('id_test',$idTest);
    $query['questions'] = $this->db->get('questions')->result();

    $i=0;
    foreach ($query['questions'] as $question) {
        $this->db->select('id_answer,response,value');
        $this->db->where('id_quest',$question->id_quest);
        $query['questions'][$i]->answer = $this->db->get('answer')->result();
        $i++;
    }
    return $query;

person Sasa    schedule 21.09.2016    source источник
comment
либо вы используете цикл, либо вы записываете каждую строку того, что было в цикле, для того, что возвращают ваши запросы.   -  person Marc B    schedule 21.09.2016
comment
так что нельзя писать по другому, что я уже писал?   -  person Sasa    schedule 21.09.2016
comment
Да, вы можете использовать while, но цикл обязателен.   -  person Phiter    schedule 21.09.2016


Ответы (3)


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

SELECT 
t.id_test, t.testName, t.description, t.time, t.type, t.sum,
q.id_quest, q.inquiry,
a.id_answer, a.response, a.value
FROM tests AS t
LEFT JOIN questions AS q ON q.id_test = t.id_test
LEFT JOIN answers AS a ON a.id_quest = q.id_quest
WHERE t.id_test = $idTest;

Тогда ваш код будет выглядеть примерно так:

<?php
// your database info here
$db_host = '';
$db_user = '';
$db_pass = '';
$db_name = '';

$con = mysqli_connect($db_host,$db_user,$db_pass,$db_name);
if($con->connect_error)
    die('Connect Error (' . mysqli_connect_errno() . ') '. mysqli_connect_error());

$query = "SELECT 
t.id_test, t.testName, t.description, t.time, t.type, t.sum,
q.id_quest, q.inquiry,
a.id_answer, a.response, a.value
FROM tests AS t
LEFT JOIN questions AS q ON q.id_test = t.id_test
LEFT JOIN answers AS a ON a.id_quest = q.id_quest
WHERE t.id_test = ?";

if (!$stmt = $con->prepare($query))
    die('Prepare Error: ' . $con->error);

$idTest = 2;
if (!$stmt->bind_param('i', $idTest))
    die('Bind Parameters Error ' . $stmt->error);

if (!$stmt->execute())
    die('Select Query Error ' . $stmt->error);

while ($stmt->fetch())
{
// get each resulting answer row, complete with associated question id and test id
}
$stmt->close();
$con->close();
person Rebecca Close    schedule 21.09.2016

Судя по тому, что я понял из вашего вопроса, вы хотите присоединиться к столам. Я думаю, у вас должно получиться что-то вроде этого:

SELECT test_table.test_name,
       qestion_table.question, 
       answer_table.answers 
FROM test_table
INNER JOIN questions_table 
on questions_table.id_test = test_table.id_test
INNER JOIN answers_table
ON answers_table.id_quest = questions_table.id_quest
WHERE test_table.id_test = ?

Это должно вернуть весь набор результатов как один объект, а не запрашивать базу данных несколько раз.

person bos570    schedule 21.09.2016
comment
Я бы также отсортировал вывод по test_name, question, answer, если результаты должны обрабатываться как простой массив или вывод напрямую для поддержания группировки. - person symcbean; 21.09.2016

Я бы полностью изучил использование 'where_in' вместо того, чтобы бросать тонны запросов в вашу базу данных.

i.e..

//...

$this->db->select('id_quest,inquiry'); 
$this->db->where('id_test',$idTest);
$query['questions'] = $this->db->get('questions')->result();

$questionIds = array();

foreach($query['questions'] as $question)
     $questionIds[] = $question->id_quest;

$this->db->select('id_answer,response,value');
$this->db->where_in('id_quest', $questionIds);
$answers = $this->db->get('answer')->result();

$i=0; // <<< Idk what the main purpose of this is, 
      //     but you do know you can simply use '[]' appending to an array, right?
foreach ($answers as $answer) {
    $query['questions'][$i]->answer = $answer;
    $i++;
}

Также, если производительность по-прежнему является серьезной проблемой. Посмотри в кеширование. CodeIgniter очень хорошо это поддерживает.

https://www.codeigniter.com/userguide3/libraries/caching.html

P.S Также посмотрите команду соединения в CI. https://www.codeigniter.com/userguide2/database/active_record.html

person ajm113    schedule 21.09.2016
comment
Если производительность является проблемой, не используйте where_in - это заставляет конкретный путь выполнения в оптимизаторе db. Если вы обнаружили, что это ускоряет ваши запросы, то вы, вероятно, не занимались домашним хозяйством. - person symcbean; 21.09.2016