输出如何使用PDO组合来自两个MySQL表的结果

时间:2013-11-25 18:43:54

标签: php mysql sql pdo

我在MySQL中有以下两个表结构,它记录了电话会议的详细信息以及加​​入它的参与者:

表:会议:

conference_sid, date_created, date_completed, RecordURL, PIN

* date_created和* date_completed是时间戳

表:参与者:

conference_sid, call_sid, call_from, name_recording

我想输出一个简单的表,它将每个conference_sid的以下结果显示为一个单独的行:

<table>
<thead>
  <th>Date</th>
  <th>Duration</th>
  <th>Participants</th>
  <th>Recording</th>
</thead>

<tbody>
<tr id="conference_sid">
  <td>date_created</td>
  <td>duration: [date_completed - date_created in h/mm/ss]</td>
  <td>
     <li><a href="name_recording">call_from</a> [for all participants in that conference_sid]
     <li>call_from...
  </td>
  <td>
   <a href="RecordURL">Call recording</a>
  </td>
  </tr>
  <tr id="conference_sid">
    ...
  </tr>

 </tbody>
</table>

我只希望此表显示与用户的Session :: get('PIN')具有相同PIN的会议的相关结果

6 个答案:

答案 0 :(得分:4)

您可以使用GROUP_CONCAT

组合参与者
SELECT 
    conf.conference_sid,
    date_created, 
    TIMEDIFF(date_completed, date_created) AS duration,
    conf.RecordURL, 
    conf.PIN,
    GROUP_CONCAT(pid SEPARATOR ",") AS pid,
    GROUP_CONCAT(call_sid SEPARATOR ",") AS call_sid,
    GROUP_CONCAT(call_from SEPARATOR ",") AS call_from,
    GROUP_CONCAT(name_recording SEPARATOR ",") AS name_recording
FROM 
    conference conf
LEFT OUTER JOIN 
    participants p ON p.conference_sid = conf.conference_sid
WHERE 
    conf.PIN = 123
GROUP BY conf.conference_sid

请参阅有关SQLFIDDLETIMEDIFF和MySQL文档。

现在应用程序逻辑将是

<?php
  $pin = 123;
  $db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
  $stmt = $db->prepare(
    'SELECT 
        conf.conference_sid,
        date_created, 
        timediff(date_completed, date_created) AS duration,
        conf.RecordURL, 
        conf.PIN,
        GROUP_CONCAT(pid SEPARATOR ",") AS pid,
        GROUP_CONCAT(call_sid SEPARATOR ",") AS call_sid,
        GROUP_CONCAT(call_from SEPARATOR ",") AS call_from,
        GROUP_CONCAT(name_recording SEPARATOR ",") AS name_recording
    FROM 
      conference conf
    LEFT OUTER JOIN 
      participants p ON p.conference_sid = conf.conference_sid
    WHERE 
      conf.PIN = :pin
    GROUP BY conf.conference_sid');
  $stmt->bindParam(':pin', $pin);
?>
<table border="1">
<thead>
  <th>Date</th>
  <th>Duration</th>
  <th>Participants</th>
  <th>Recording</th>
</thead>

<tbody>
<?php
  $stmt->execute();
  while ($row = $stmt->fetch()) {
?>
    <tr>
      <td><?php echo $row['date_created']; ?></td>
      <td><?php echo $row['duration']; ?></td>
      <td>
        <table border="1">
          <thead>
            <th>call_sid</th>
            <th>call_from</th>
            <th>name_recording</th>
          </thead>
          <tbody>

<?php
    $length = count(explode(',', $row['pid']));
    $call_sid = explode(',', $row['call_sid']);
    $call_from = explode(',', $row['call_from']);
    $name_recording = explode(',', $row['name_recording']);
    for ($i=0; $i < $length; $i++) { 
      ?>
        <tr>
          <td> <?php echo $call_sid[$i]; ?> </td>
          <td> <?php echo $call_from[$i]; ?></td>
          <td> <?php echo $name_recording[$i]; ?> </td>
        <tr>
<?php
    }
?>
        </tbody>
        </table>
      </td>
      <td>
        <a href="<?php echo $row['RecordURL']; ?>">
        Call recording</a>
      </td>
    </tr>
<?php
  }
?>
</tbody>

您将在pid,call_sid,call_from和name_recording中使用逗号(,)分隔值获取结果集。您可以使用explode将此字符串转换为数组。

array explode ( string $delimiter , string $string [, int $limit ] )
  

返回一个字符串数组,每个字符串都是字符串的子字符串   通过将其分割成由字符串分隔符形成的边界而形成。

答案 1 :(得分:2)

我不会做PHP部分,因为我不熟悉PHP,但这里是SQL:

SELECT *
FROM `conference`, `participants`
WHERE `conference`.PIN = $PIN AND
      `participants`.conference_sid = `conference`.conference_sid

这将返回包含来自conference的信息和participants conferences的信息的行,这些信息会合并为一行。

答案 2 :(得分:0)

以下查询将为您提供显示所需的信息:

SELECT c.conference_sid
     , c.date_created
     , timediff(c.date_completed, c.date_created) AS duration
     , p.call_from
     , p.name_recording
     , c.RecordURL
  FROM conference c
  JOIN participants p
    ON c.conference_sid = p.conference_sid
 WHERE c.PIN = :PIN
 ORDER BY c.conference_sid

您需要使用嵌套循环处理结果。每次conference_sid更改时,外循环都应该前进。内部循环将显示该会议的参与者列表的每个元素。

答案 3 :(得分:0)

在这个特定的上下文中,我更喜欢使用两个独立的查询。以下是我将如何做到这一点:

<?php
  try {
    $db = new PDO('mysql:host=localhost;dbname=test', 'username', 'password');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  } catch (PDOException $e) {
    echo 'Could not connect to db';
    exit;
  }

  $stmt_conferences = $db->prepare(
    'SELECT
       date_created,
       timediff(date_completed, date_created) AS duration,
       RecordURL,
       conference_sid
     FROM
       conference
     WHERE
       PIN=:pin');
  $stmt_conferences->bindParam(':pin', $pin);

  $stmt_participants = $db->prepare(
    'SELECT
       name_recording,
       call_from
     FROM
       participants
     WHERE
       conference_sid=:confsid');
  $stmt_participants->bindParam(':confsid', $confsid);
?>
<table>
<thead>
  <th>Date</th>
  <th>Duration</th>
  <th>Participants</th>
  <th>Recording</th>
</thead>

<tbody>
<?php
  $pin = 1; /* get your PIN here */

  $stmt_conferences->execute();
  while ($row = $stmt_conferences->fetch()) {
?>
    <tr>
      <td><?php echo htmlspecialchars($row['date_created'], ENT_QUOTES); ?></td>
      <td><?php echo htmlspecialchars($row['duration'], ENT_QUOTES); ?></td>
      <td>
<?php
    $confsid = $row['conference_sid'];
    $stmt_participants->execute();
    while ($participant = $stmt_participants->fetch()) {
?>
        <li><a href="<?php echo htmlspecialchars($participant['name_recording'], ENT_QUOTES); ?>">
            <?php echo htmlspecialchars($participant['call_from'], ENT_QUOTES); ?>
            </a>
<?php
    }
?>
      </td>
      <td>
        <a href="<?php echo htmlspecialchars($row['RecordURL'], ENT_QUOTES); ?>">
        Call recording</a>
      </td>
    </tr>
<?php
  }
?>
</tbody>

请注意,您必须添加一些代码来处理错误并正确转义您回显的所有数据(您真的可以信任您的数据库吗?)。此外,元素ID在整个文档中应该是唯一的,您的页面中只能有一个id="conference_sid"。改为使用类。

修改

如果您真的可以信任您的数据库,那么您可以使用以下代码输出字段的内容:

<?php echo $row['call_from']; ?>

但是如果RecordURL包含例如以下字符串会发生什么?

<script>alert("I am injecting some code....");</script>

将会在页面中注入一些不需要的代码,因此每次需要回显一些输出时,最好使用像htmlspecialchars()这样的安全函数:

<?php echo htmlspecialchars($row['call_from'], ENT_QUOTES); ?>
这样,任何不需要的代码都不会有害。

我还为handle errors添加了一个基本的TRY / CATCH构造。

希望这有帮助!

答案 4 :(得分:0)

这将是我的看法,它使用2个单独的查询来保持数据分离。我使用fetchAll()来简洁,但这可能会有性能问题,幸运的是这可以容纳。我没有进行任何错误检查,如果您需要或有疑问,请询问

<?php
// assume $db is a PDO connection to the database
/* @var $db PDO */
$q = 'SELECT conference_sid, date_created, date_completed, RecordURL, PIN'
    .' FROM conference';
// we need these
$conferences = $db->query($q)->fetchAll(PDO::FETCH_CLASS,'stdClass');
// let's group them as CSV, and concatenate the contents with ":"
$q = 'SELECT conference_sid,GROUP_CONCAT(CONCAT_WS(":",call_from,name_recording)) AS parts '
    .' FROM participants GROUP BY conference_sid';
$conf_parts = array();
foreach ($db->query($q)->fetchAll(PDO::FETCH_CLASS,'stdClass') as $parts) {
  // save the participants as an array, their data is still joined though
  $conf_parts[$parts->conference_sid] = explode(',',$parts->parts);
  // their contents will be exploded later
}
?>
<table>
  <thead><th>Date</th><th>Duration</th><th>Participants</th><th>Recording</th></thead>
  <tbody><?php foreach ($conferences as $conference) {
    $csid = $conference->conference_sid;
    // http://stackoverflow.com/questions/3108591/calculate-number-of-hours-between-2-dates-in-php
    // Create two new DateTime-objects...
    $date1 = new DateTime($conference->date_completed);
    $date2 = new DateTime($conference->date_created);
    // The diff-methods returns a new DateInterval-object...
    $diff = $date2->diff($date1);
    ?><tr id="<?php echo $csid; ?>">
      <td><?php echo $conference->date_created; ?></td>
      <td><?php echo $diff->format('H/i/s'); ?></td>
      <td>
        <ul><?php foreach ($conf_parts[$csid] as $participant) {
          // we have each participant for this conference call
          list ($call_from, $name_recording) = explode($participant,':');
          // and now we have the required data from each participant
          ?><li><a href="<?php echo $name_recording ?>"><?php echo $call_from; ?></a></li><?php
        } ?></ul>
      </td>
      <td>
        <a href="<?php echo $conference->RecordURL; ?>">Call recording</a>
      </td>
    </tr><?php
    } ?></tbody>
</table>

答案 5 :(得分:0)

首先,我们需要得到我们的结果。

$vPIN = $_SESSION['PIN']; // or however you get your user's pin from session
$vQuery = "SELECT * FROM conference AS a LEFT JOIN participants as B USING (conference_sid) WHERE a.PIN='$vPIN'";
$oResult = $oDB->execute($vQuery);
$aRows = $oResult->fetchAll(PDO::FETCH_ASSOC);

注意前缀:$ v如果对于一个简单的变量,$ o表示一个ressource(我喜欢将其视为一个对象),$ a表示一个数组。这只是为了我的精神健康。

所以现在,我们有一个数组,可能非常大,包含会议桌中的每一行,与参与者中的每一对应行相对应。很好,现在让我们构建一个有一些含义的数组。

foreach($aRows as $aRow) // maybe a bit confusing but the 's' changes everything: all rows vs one row
 {if (!isset($aConferences[$aRow['conference_sid']]['infos']))
   {$aConferences[$aRow['conference_sid']]['infos']['date_created'] = $aRow['date_created'];
    $aConferences[$aRow['conference_sid']]['infos']['date_completed'] = $aRow['date_completed'];
    $aConferences[$aRow['conference_sid']]['infos']['record_url'] = $aRow['RecordURL'];
    $aConferences[$aRow['conference_sid']]['infos']['pin'] = $aRow['PIN'];}
  $aConferences[$aRow['conference_sid']]['participants'][] = $aRow['call_from'];}

所以这里发生的是,对于每一行,如果没有设置相应的conference_sid的信息,它们将是,然后我们为该会议的每个call_from创建一个从0到x的列表。具有虚拟值的该数组的print_r:

[1627]['infos']['date_created'] = 2013-11-26
               ['date_completed'] = 2013-11-29
               ['record_url'] = 'http://whatever.com'
               ['PIN'] = 139856742
      ['participants'][0] = Bob
                      [1] = gertrude
                      [2] = Foo
[8542]['infos']['date_created'] = 2013-12-01
               ['date_completed'] = 2013-12-02
               ['record_url'] = 'http://whateverelse.com'
               ['PIN'] = 584217
      ['participants'][0] = Family Guy
                      [1] = aragorn
                      [2] = obama
                      [3] = Loki

所以这里有一个很好的数组,我们可以用它来构建一个html表!让我们这样做

$vHTML = '<table>
          <thead>
            <th>Date</th>
            <th>Duration</th>
            <th>Participants</th>
            <th>Recording</th>
          </thead>
          <tbody>';
foreach ($aConferences as $conference_sid => $aConference) // notice the s and no s again
 {$vHTML.= '<tr id="' . $conference_sid . '">';
  $vDateCreated = $aConference['infos']['date_created'];
  $vDateCompleted = $aConference['infos']['date_completed'];
  $vHTML.= '<td>' . $vDateCreated . '</td>';
  $vHTML.= '<td>' . date('Y-m-d',(strtotime($vDateCompleted) - strtotime($vDateCreated))) . '</td>'; // you might have to debug that date diff for yourself.
  $vHTML.= '<td><ul>'; // here a foreach for the participants
  foreach ($aConference['participants'] as $call_from)
   {$vHTML.= '<li>' . $call_from . '</li>';}
  $vHTML.= '</ul></td>';
  $vHTML.= '<td>' . $aConference['infos']['record_url'] . '</td>';
  $vHTML.= '</tr>';}
$vHTML.= '</tbody></table>';

所以这里:为每个会议创建一个包含信息的表格行,然后为每个参与者在列表中添加一个列表项目。如果你想要任何精确度,请发表评论。

哦,不要忘记用$ vHTML做点什么。比如echo $ vHTML:)