【问题标题】:Optimize Subselect Search query优化子选择搜索查询
【发布时间】:2014-01-17 12:25:01
【问题描述】:

在我的 MYSQL 数据库中,我有多个这样的表:

reference:

------------------------------
| id | title   | subtitle    |
| 1  | Test    | Just a test |
| 2  | Another | Second      |
| 3  | Last    | Third       |
------------------------------

author:

-----------------------------
| id | firstname | lastname |
| 1  | Peter     | Pan      |
| 2  | Foo       | Bar      |
| 3  | Mr.       | Handsome |
| 4  | Steve     | Jobs     |
-----------------------------

keyword:

----------------
| id | keyword |
| 1  | boring  |
| 1  | lame    |
----------------

reference_author_mm:

---------------------------
| uid_local | uid_foreign |
| 1         | 1           |
| 1         | 2           |
| 2         | 1           |
| 2         | 2           |
| 2         | 4           |
| 3         | 1           |
| 3         | 2           |
| 3         | 4           |
---------------------------

所有表都有一个n:mreferences 表的关系表。通过一个查询,我想SELECT所有参考文献并按作者姓名或关键字等过滤/排序它们。所以我想要的输出是这样的:

用户按title搜索:

 ------------------------------------------------------------------------------
| id | title   | subtitle    | authors                        | keywords     |
| 1  | Test    | Just a test | Peter Pan, Foo Bar             | boring       |
| 2  | Another | Second      | Peter Pan, Foo Bar, Steve Jobs | boring, lame |
| 3  | Last    | Third       | Peter Pan, Foo Bar, Steve Jobs | boring, lame |
-------------------------------------------------------------------------------

此时我有一个很长的构造,它不太工作:

SELECT r.* , Authors.author AS authors, Keywords.keyword AS keywords
FROM references AS r
LEFT OUTER JOIN (
    SELECT r.pid AS pid,
        GROUP_CONCAT(CONCAT_WS(\' \', CONCAT(p.lastname, \',\'), p.prefix, p.firstname) SEPARATOR \'; \') AS author
    FROM reference AS r
    LEFT JOIN reference_author_mm r2p ON r2p.uid_local = r.uid
    LEFT JOIN author p ON p.uid = r2p.uid_foreign
    GROUP BY r.pid
) Authors ON r.pid = Authors.pid

对于与references 的每个n:m 关系,此LEFT OUTER JOIN 语句存在多次。查询这些表的最简单方法是什么。请记住,我需要例如ODER BY作者或通过参考的关键字搜索。

编辑:

我尝试的新查询:

SELECT r.*,
    GROUP_CONCAT(CONCAT_WS(\' \', CONCAT(a.lastname, \',\'), a.prefix, a.firstname) SEPARATOR \'; \') AS authors,
    GROUP_CONCAT(CONCAT_WS(\' \', k.name)) AS keywords,
    GROUP_CONCAT(CONCAT_WS(\' \', c.name)) AS categories,
    GROUP_CONCAT(CONCAT_WS(\' \', p.name)) AS publishers
FROM reference AS r
LEFT OUTER JOIN (
    SELECT * FROM reference_author_mm AS rha
        INNER JOIN author AS a ON a.uid = rha.uid_foreign
) AS a ON a.uid_local = r.uid
LEFT OUTER JOIN (
    SELECT * FROM reference_keyword_mm AS rhk
        INNER JOIN keywords AS k ON k.uid = rhk.uid_foreign
) AS k ON k.uid_local = r.uid

【问题讨论】:

  • 请再提供几行显示所需结果。
  • 完成。感谢您的关注。

标签: mysql sql query-optimization


【解决方案1】:

我试图根据您在问题中指定的表结构(不是我在您的查询中看到的)使我的查询尽可能清晰。 您可能需要更改一些字段/表名称。

您可以在这里查看查询结果:SQLFiddle demo

SELECT
    r.id
    ,r.title
    ,r.subtitle
    ,ra.authors
    ,rk.keyworks
FROM
    reference r
    LEFT JOIN
        (SELECT
            r.id
            ,GROUP_CONCAT(CONCAT(a.firstname, ' ', a.lastname) ORDER BY CONCAT(a.firstname, ' ', a.lastname) SEPARATOR ', ') as authors
        FROM
            reference r
            LEFT JOIN reference_author_mm r2a
                ON r.id = r2a.uid_local
            LEFT JOIN author a 
                ON a.id = r2a.uid_foreign
        GROUP BY
            r.id) ra
        ON ra.id = r.id
    LEFT JOIN
        (SELECT
            r.id
            ,GROUP_CONCAT(k.keyword ORDER BY k.keyword SEPARATOR ', ') as keyworks
        FROM
            reference r
            LEFT JOIN reference_keyword_mm r2k
                ON r.id = r2k.uid_local
            LEFT JOIN keyword k
                ON k.id = r2k.uid_foreign
        GROUP BY
            r.id) rk
        ON rk.id = r.id 
ORDER BY
    r.id

如果您需要按姓氏排序作者姓名,只需将CONCAT(a.firstname, ' ', a.lastname) 更改为CONCAT(a.lastname, ' ', a.firstname)

如果您有任何问题,请随时更新我的​​ sqlfiddle 演示中的表结构,并给我留言说明您面临的问题并举例说明。

【讨论】:

  • 该示例运行良好。加价有很大帮助。谢谢!
【解决方案2】:

也许?

SELECT r.*,
GROUP_CONCAT(CONCAT_WS(\' \', CONCAT(a.lastname, \',\'), a.prefix, a.firstname) SEPARATOR \'; \')) AS author,
GROUP_CONCAT(CONCAT_WS(\' \', k.keywords) AS keywords
FROM references AS r
LEFT OUTER JOIN (SELECT * FROM references_has_authors AS rha INNER JOIN authors AS a ON a.id = rha.authors_id) AS a ON a.references_id = r.id
LEFT OUTER JOIN (SELECT * FROM references_has_keywords AS rhk INNER JOIN keywords AS k ON k.id = rhk.references_id) AS k ON k.references_id = r.id
GROUP BY r.id;

作为最后的努力,也许在应用程序中做?

【讨论】:

  • 这个主意不错!我从您的答案中删除了一些语法错误并进行了尝试,但不幸的是,authorskeywords 字段的结果始终为空。我会用新的查询更新我的问题。
【解决方案3】:
SELECT dt1.id,dt1.title,dt1.subtitle,dt1.author_name,dt2.keyword_name
  FROM ( SELECT r.id,r.title,r.subtitle,GROUP_CONCAT(CONCAT(a.firstname,' ',a.lastname)) author_name
       FROM `reference` r
       LEFT JOIN `reference_author_mm` mm ON (r.id = mm.uid_local)
       LEFT JOIN `author` a ON (mm.uid_foreign = a.id)
       GROUP BY 1,2,3
       )dt1
      JOIN( SELECT r.id,r.title,r.subtitle,GROUP_CONCAT(keyword) keyword_name
          FROM reference r
          LEFT JOIN `reference_keyword_mm` km ON (km.uid_local = r.id)
          LEFT JOIN `keywords` k ON (k.id = km.uid_foreign)
          GROUP BY 1,2,3
          )dt2 ON (dt1.id = dt2.id);

【讨论】:

  • @BoltClock :尝试为此发布答案,而不是删除其他用户的帖子。
  • 所有链接到当前reference的关键字都应该在一个字段中,并且,分开。
  • 是的,上面的查询将所有引用链接到,在作者列下分隔。如果不发布你得到的结果
  • 我需要同样的keywords
  • 我已经完善了我的查询。检查它是否满足您的问题。如果是,则将其标记为已接受
猜你喜欢
  • 1970-01-01
  • 2018-02-23
  • 1970-01-01
  • 1970-01-01
  • 2016-06-14
  • 2013-03-16
  • 2016-01-06
相关资源
最近更新 更多