优化子选择搜索查询

时间:2014-01-17 12:25:01

标签: mysql sql query-optimization

在我的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:m表有一个references关系表。通过一个查询,我想SELECT所有引用,按照作者姓名或关键字等过滤/订购。所以我想要的输出是这样的:

用户搜索标题

 ------------------------------------------------------------------------------
| 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

LEFT OUTER JOIN语句与n:m的每个references关系存在多次。查询这些表的最简单方法是什么。请记住,我需要例如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

3 个答案:

答案 0 :(得分: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演示中的表格结构,并留下评论,说明您面临的问题并给我举例。

答案 1 :(得分:0)

也许?

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;

作为最后的努力,也许在申请中做什么?

答案 2 :(得分:0)

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);