简体   繁体   English

在PHP / MySql中通过单个查询从多个表中获取“相关”数据?

[英]get 'related' data from several tables with a single query in PHP/MySql?

I'm developing a small PHP app from scratch to practice/learn. 我正在从头开发一个小型PHP应用程序到实践/学习。 The goal is to be able to create articles. 目标是能够创建文章。 Each article can have tags and images, stored in their own tables. 每篇文章都可以将标签和图像存储在自己的表格中。 Since an article can have many tags and a single tag can be present in many articles, I also created a 'tag/article' association table. 由于一个文章可以有很多标签,并且一个标签可以出现在许多文章中,所以我还创建了一个“标签/文章”关联表。

Now, when I want to edit or display an article, I get its data (plus tags and images) by doing several DB requests... for example, given an article id, I do something like: 现在,当我要编辑或显示文章时,我通​​过执行几个数据库请求来获取其数据(加上标签和图像)……例如,给定文章ID,我可以执行以下操作:

$article = getArticle($articleId);
$tags = getArticleTags($articleId);
$images = getArticleImages($articleId);

It works, but I'm not sure if it's a clean approach and good performance-wise. 它可以工作,但是我不确定这是否是一种干净的方法并且性能还是不错的。 So I was wondering, can this be done by using a single query? 所以我想知道,是否可以通过使用单个查询来完成? I tried but got a bit confused with UNIONs and JOINs. 我尝试过,但是对UNION和JOIN有点困惑。 If not, is there any better/recommended approach to achieve this? 如果没有,是否有更好/建议的方法来实现这一目标?

The (simplified) tables I'm using are: 我正在使用的(简化)表是:

articles table: 文章表:

┌-----┬------------------┬------------------------┐
│ id  │ title            │ dateCreated            │
├-----┼------------------┼------------------------┤
│ 1   │ some article     │ 2015-03-17 12:38:49    │
├-----┼------------------┼------------------------┤
│ 2   │ article two      │ 2015-03-17 15:00:24    │
└-----┴------------------┴------------------------┘ 

tags table: 标签表:

┌-----┬------------------┬------------------------┐
│ id  │ name             │ dateCreated            │
├-----┼------------------┼------------------------┤
│ 1   │ php              │ 2015-03-17 15:01:05    │
├-----┼------------------┼------------------------┤
│ 2   │ jquery           │ 2015-03-17 15:24:12    │
└-----┴------------------┴------------------------┘ 

tag-article association table: 标签-文章关联表:

┌-----┬--------┬-------------┬------------------------┐
│ id  │ tagId  │ articleId   │ dateCreated            │
├-----┼--------┼-------------┼------------------------┤
│ 1   │ 1      │ 1           │ 2015-03-17 15:01:06    │
├-----┼--------┼-------------┼------------------------┤
│ 2   │ 2      │ 1           │ 2015-03-17 15:24:58    │
├-----┼--------┼-------------┼------------------------┤
│ 3   │ 1      │ 2           │ 2015-03-17 15:30:38    │
└-----┴--------┴-------------┴------------------------┘

article-images table: article-images表:

┌-----┬-----------┬-------------┬------------------------┐
│ id  │ fileName  │ articleId   │ dateCreated            │
├-----┼-----------┼-------------┼------------------------┤
│ 1   │ pic1.jpg  │ 1           │ 2015-03-17 16:05:26    │
├-----┼-----------┼-------------┼------------------------┤
│ 2   │ pic2.jpg  │ 1           │ 2015-03-17 16:06:29    │
├-----┼-----------┼-------------┼------------------------┤
│ 3   │ dog.jpg   │ 2           │ 2015-03-17 17:00:14    │
├-----┼-----------┼-------------┼------------------------┤
│ 4   │ cat.jpg   │ 2           │ 2015-03-17 17:01:06    │
├-----┼-----------┼-------------┼------------------------┤
│ 5   │ bird.jpg  │ 2           │ 2015-03-17 17:02:34    │
└-----┴-----------┴-------------┴------------------------┘

Also, I'm using PDO this way, for example, to get an article: 另外,我以这种方式使用PDO,例如,获得一篇文章:

    public function getArticleById($id){
        $sql = "SELECT * FROM articles WHERE id=:id LIMIT 1";
        $query = $this->db->prepare($sql);
        $parameters = array(':id' => $id);
        $result = $query->execute($parameters);
        return ($result) ? $query->fetch() : 0;
    }

Any input will be greatly appreciated. 任何输入将不胜感激。 Thanks! 谢谢!


UPDATE: 更新:

@Adrian's answer is close to what I'm looking for and partially solves the question. @Adrian的答案与我正在寻找的答案很接近,并且可以部分解决问题。 It returns the following 它返回以下内容 在此处输入图片说明

The thing is that the id columns are ambiguous and I can't figure out how to end up with a clean array like this, ideally: 问题是id列是模棱两可的,理想情况下,我无法弄清楚如何以这样的干净数组结尾:

Array
(
    [title] => some article
    [id] => 1
    [tags] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => php
                )

            [1] => Array
                (
                    [id] => 2
                    [name] => jquery
                )

        )

    [images] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [fileName] => pic1.jpg
                )

            [1] => Array
                (
                    [id] => 2
                    [fileName] => pic2.jpg
                )

        )

)

Then, combining both Daniel's and Adrian's answers, I ended up with this query, which returns something more readable that (I guess) I could process to achieve the above mentioned array (I imagine that iterating and removing duplicates): 然后,结合丹尼尔(Daniel)和阿德里安(Adrian)的答案,我得到了以下查询,该查询返回了更具可读性的(我想)我可以处理以实现上述数组(我想迭代并删除重复项):

SELECT 
    a.id, 
    a.title, 
    a.dateCreated as articleDate,
    i.id as imageId,
    i.fileName as imageFile,
    t.id as tagId,
    t.name as tagName
FROM 
    articles a
JOIN 
    article_tags ta ON a.id = ta.articleId
JOIN
    tags t ON ta.tagId = t.id

JOIN 
    images i ON a.id = i.articleId


WHERE 
    a.id = 1

This returns: 返回:

在此处输入图片说明

performance-wise, since this possible solution returns many rows with duplicated data (depending on how many tags and images are associated with an article). 性能方面,因为这种可能的解决方案将返回许多行,这些行具有重复的数据(取决于与文章关联的标签和图像的数量)。 Is this better than doing the initial multiple calls I started with? 这比进行我最初发起的多个通话更好吗?

SELECT 
    a.id, 
    a.title, 
    a.dateCreated as articleDate,
    i.fileName as imageFile,
    t.name as tagName
FROM 
    articles a
JOIN 
    images i ON a.id = i.articleId
JOIN 
    tag_article ta ON a.id = ta.articleId
JOIN
    tags t ON ta.articleId = t.id
WHERE 
    a.id = ?

Try this code: 试试这个代码:

EDIT: 编辑:

$sql = "SELECT
articles.id, 
articles.title, 
articles.dateCreated as articleDate,
article-images.id as imageId,
article-images.fileName as imageFile,
tags.id as tagId,
tags.name as tagName
FROM articles
JOIN tag-article ON articles.id = tag-article.articleId
JOIN tags ON tag-article.tagId = tags.id
JOIN article-images ON article-images.articleId = articles.id
WHERE articles.id=:id"

$query = $this->db->prepare($sql);
$parameters = array(':id' => $id);
$result = $query->execute($parameters);
return ($result) ? $query->fetch() : 0;

?>

I've found a way to achieve what I wanted, by combining the answers posted by @Adrian and @Daniel who pointed me in the right direction (thanks!) and adding the use of CONCAT, GROUP_CONCAT and CAST (to mix int and varchar). 通过结合@Adrian和@Daniel的答案(找到正确的方向(谢谢!))并添加CONCAT,GROUP_CONCAT和CAST(混合使用int和varchar),我找到了一种实现我想要的方法)。

I upvoted both answers, which solved the problem partially, but I thought I should post my own answer since (I think) is a cleaner solution, at least for what I wanted, and it may help someone else. 我对两个答案都提出了建议,但部分解决了问题,但是我认为我应该发表自己的答案,因为(我认为)这是一种更清洁的解决方案,至少对于我想要的解决方案而言,它可能会对其他人有所帮助。

Here's the SQL 这是SQL

SELECT 
  a.id, 
  a.title, 
  GROUP_CONCAT( DISTINCT CAST( t.id AS CHAR( 50 ) ) ,  ':', t.name ORDER BY t.id SEPARATOR  ',' ) AS  'tags', 
  GROUP_CONCAT( DISTINCT CAST( i.id AS CHAR( 50 ) ) ,  ':', i.fileName ORDER BY i.id SEPARATOR  ',' ) AS  'images'
FROM 
  articles a
JOIN 
  article_tags ta ON a.id = ta.articleId
JOIN 
  images i ON a.id = i.articleId
JOIN 
  tags t ON ta.tagId = t.id
WHERE 
  a.id = :id

This query returns the following, with id = 1: 该查询返回以下ID为1的内容:

在此处输入图片说明

A single row containing the article's data, its tags and images in a id:value format, which I think it's very easy to parse in PHP and can even be used to return a json string by just adding another concat. 单行包含id:value格式的文章数据,其标签和图像,我认为用PHP解析起来很容易,甚至可以通过添加另一个concat来返回json字符串。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM