在属于且不属于的3个表中选择mysql数据?

时间:2015-10-13 12:20:49

标签: php mysql pdo

我有以下表格:

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| c_id        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| c_name      | varchar(255) | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

文章

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| a_id        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| a_name      | varchar(255) | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

Course_Articles

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| ca_id       | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| a_id        | bigint(20)   | NO   |     | NULL    |                |
| c_id        | bigint(20)   | NO   |     | NULL    |                |
| t_id        | bigint(20)   | NO   |     | NULL    |                |
| sort_order  | int(11)      | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

学期(或学期)

+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| t_id        | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| t_name      | varchar(255) | NO   |     | NULL    |                |
| c_id        | bigint(20)   | NO   |     | NULL    |                |
| sort_order  | int(11)      | NO   |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

我需要按如下方式显示这些表中的数据:

课程名称:现代气体提取

文章:

  • 简介
  • 气体提取技术概述

  • 第1学期:传统技术

    • 煤矿甲烷
    • 另一种传统技术
  • 另一篇不在术语

  • 的文章
  • 另一个

  • 第2学期 <非传统技术

    • 地下煤气化
    • 煤层气
    • 水力压裂
  • 结论

我知道这些数据可能会受益于嵌套/树。但这是我必须要合作的。如您所见,文章可以属于一个术语或是独立的。

关于如何根据示例有效地查询上面的输出,我感到有点难过。

<?php
// UPDATED with UNION as suggested
try {
$stmt = $dbh->prepare(
    "SELECT ca . * , a.a_name, t.t_name
FROM Course_Article AS ca 
LEFT JOIN Article AS a ON a.a_id = ca.ca_id
LEFT OUTER JOIN Term AS t ON t.t_id = ca.t_id
WHERE ca.c_id = '2'
UNION SELECT te.t_name, te.t_id, te.c_id
FROM Term AS te
WHERE te.t_id = '2'");

$last_term_id = -1;

$stmt->execute();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
  if ($last_term_id != $row['t_id']) {
    echo "<b>" . $row['t_name'] . "</b><br />";
    $last_term_id = $row['t_id'];
  }
  echo $row['a_name'] . "<br />";
  }
 } catch(PDOException $e) {
  echo 'Error : '. $e->getMessage();
  exit();
  }
?>

谢谢

1 个答案:

答案 0 :(得分:0)

所以这里有一个想法如何使用union来实现:第一部分获取所有术语(也是空术语)和它们下面的文章,第二部分获取所有属于该课程但不属于任何术语的其他文章。希望我在这里没有包含太多的逻辑/错误错误。

select t.t_name, ca.*, a.a_name
from Term t
left outer join Course_Article ca ON ca.t_id = t.t_id
left outer join Article a ON a.a_id = ca.a_id
where t.c_id = '2'

UNION

select null as t_name, ca.*, a.a_name
from Course_Articles ca
left outer join Article a ON a.a_id = ca.a_id
where ca.c_id = '2' and ca.t_id is null

此外,如果您需要稍微订购结果(如果排序顺序在课程文章和术语之间是通用的,则不知道),您可以稍微扩展一下(将最终结果所需的任何列添加到主要内容中)选择):

select t_name, a_name, sort_column
FROM
(
    select t.t_name, ca.*, a.a_name, t.sort_order as sort_column
    from Term t
    left outer join Course_Article ca ON ca.t_id = t.t_id
    left outer join Article a ON a.a_id = ca.a_id
    where t.c_id = '2'

    UNION

    select null as t_name, ca.*, a.a_name, ca.sort_order as sort_column
    from Course_Articles ca
    left outer join Article a ON a.a_id = ca.a_id
    where ca.c_id = '2' and ca.t_id is null
) dt
order by sort_column ASC