Не знаю, как ограничить внутренний запрос SQL в PHP - PullRequest
0 голосов
/ 20 декабря 2018

Тонны поиска S / O до сих пор были чрезвычайно полезны ... и следующее почти работает.Моя проблема в том, что второй SQL-запрос возвращает ВСЕ «ингредиенты» для КАЖДОГО «рецепта», тогда как в рецепте № 1 были ингредиенты A, C, F, а в рецепте № 2 были ингредиенты A, G, H.Как ограничить второй запрос, чтобы возвращать только ингредиенты для рецепта в текущем цикле?Я был бы очень благодарен за помощь мастера PHP / SQL.

Структура БД с отношением «многие ко многим»:

RECIPE (recid, title) 
REC_ING (recid, ingid) 
INGREDIENT (ingid, ingredient)

Вот мой PHP-код:

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "recipe";
try {
  $db = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
}
catch(PDOException $e) {
   echo "Error: " . $e->getMessage();
}
$xml = new XMLWriter();
$xml->openURI('stackexch.xml');
$xml->setIndent(2);
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('recipes');
$recipe = $db->query("SELECT * FROM recipe");
foreach ($recipe as $row) {
  $xml->startElement('recipe');
  $xml->startElement('title');
  $xml->writeRaw($row['title']);
  $xml->endElement();
  $ingredient = $db->query("SELECT ingredient FROM recipe, rec_ing, ingredient WHERE recipe.recid=rec_ing.recid AND ingredient.ingid=rec_ing.ingid");
  foreach ($ingredient as $subrow) {
    $xml->startElement('ingredient');
    $xml->writeRaw($subrow['ingredient']);
    $xml->endElement();
    }
  $xml->endElement();
}
$xml->endElement();
$xml->endDocument();
$xml->flush();
?>

И вот что возвращается:

<?xml version="1.0" encoding="UTF-8"?>
<recipes>
  <recipe>
    <title>Recipe #1</title>
    <ingredient>ingredient A</ingredient>
    <ingredient>ingredient C</ingredient>
    <ingredient>ingredient F</ingredient>
    <ingredient>ingredient G</ingredient>
    <ingredient>ingredient H</ingredient>
  </recipe>
  <recipe>
    <title>Recipe #2</title>
    <ingredient>ingredient A</ingredient>
    <ingredient>ingredient C</ingredient>
    <ingredient>ingredient F</ingredient>
    <ingredient>ingredient G</ingredient>
    <ingredient>ingredient H</ingredient>
  </recipe>
</recipes>

Ответы [ 3 ]

0 голосов
/ 20 декабря 2018

Это потребляет ресурсы:

SELECT * FROM recipe

Все же вы используете только [заголовок], так зачем тянуть все столбцы?

Это выполняется для каждой строки, возвращаемой сверху:

SELECT ingredient 
FROM recipe, rec_ing, ingredient 
WHERE recipe.recid=rec_ing.recid AND ingredient.ingid=rec_ing.ingid

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

SELECT r.title, i.ingredient 
FROM recipe r
INNER JOIN rec_ing ON r.recid=rec_ing.recid 
INNER JOIN ingredient i ON i.ingid=rec_ing.ingid

Также обратите внимание, что более 25 лет назад ANSI формализовала набор объединений, которые вы должны попробоватьпринять.2 подсказки для этого:

  1. запретить использование запятых между именами таблиц в предложении from и
  2. , если условие имеет две ссылки на таблицу, это условие принадлежит JOIN, например recipe .recid = rec_ing .recid (видите? У которого есть ссылка на таблицу на каждой стороне равенства, это условие соединения)

OneПоследнее предложение: SQL-запрос не должен быть отдельной строкой в ​​коде PHP.

0 голосов
/ 20 декабря 2018

Добро пожаловать в Stackoverflow.Вам нужно добавить RECIPE.recid='.$row['recid'] в предложении where.

Однако, с моей точки зрения, вы можете упростить логику, используя только один запрос.Я бы предложил использовать внутренние объединения для включения информации из нескольких таблиц.

SELECT *
FROM recipe AS r
INNER JOIN rec_ing AS ri ON ri.recid=r.recid
INNER JOIN INGREDIENT AS i ON i.ingid=ri.ingid;
0 голосов
/ 20 декабря 2018

Предполагая, что recid является идентификатором рецепта.Попробуйте это:

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "recipe";
try {
  $db = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
}
catch(PDOException $e) {
   echo "Error: " . $e->getMessage();
}
$xml = new XMLWriter();
$xml->openURI('stackexch.xml');
$xml->setIndent(2);
$xml->startDocument('1.0', 'UTF-8');
$xml->startElement('recipes');
$recipe = $db->query("SELECT * FROM recipe");
foreach ($recipe as $row) {
  $xml->startElement('recipe');
  $xml->startElement('title');
  $xml->writeRaw($row['title']);
  $xml->endElement();
  $ingredient = $db->query("SELECT ingredient FROM recipe, rec_ing, ingredient WHERE recipe.recid=rec_ing.recid AND ingredient.ingid=rec_ing.ingid AND recipe.recid = " . $row['recid']);
  foreach ($ingredient as $subrow) {
    $xml->startElement('ingredient');
    $xml->writeRaw($subrow['ingredient']);
    $xml->endElement();
    }
  $xml->endElement();
}
$xml->endElement();
$xml->endDocument();
$xml->flush();
?>

Поскольку вы уже выбираете из таблицы рецептов, вам не нужно выбирать из нее снова.Вероятно, вы могли бы упростить код следующим образом:

<?php
    $servername = "localhost";
    $username = "root";
    $password = "";
    $dbname = "recipe";
    try {
      $db = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
    }
    catch(PDOException $e) {
       echo "Error: " . $e->getMessage();
    }
    $xml = new XMLWriter();
    $xml->openURI('stackexch.xml');
    $xml->setIndent(2);
    $xml->startDocument('1.0', 'UTF-8');
    $xml->startElement('recipes');
    $recipe = $db->query("SELECT * FROM recipe");
    foreach ($recipe as $row) {
      $xml->startElement('recipe');
      $xml->startElement('title');
      $xml->writeRaw($row['title']);
      $xml->endElement();
      $ingredient = $db->query("SELECT ingredient FROM rec_ing, ingredient WHERE ingredient.ingid=rec_ing.ingid AND rec_ing.recid = " . $row['recid']);
      foreach ($ingredient as $subrow) {
        $xml->startElement('ingredient');
        $xml->writeRaw($subrow['ingredient']);
        $xml->endElement();
        }
      $xml->endElement();
    }
    $xml->endElement();
    $xml->endDocument();
    $xml->flush();
    ?>

Как правило, я бы не рекомендовал объединять переменные в запросе, но в этом случае это безопасно, поскольку вы уже выбираете идентификатор из базы данных.

...