简化MySQL嵌套SELECT

时间:2012-11-16 09:54:24

标签: mysql select nested

id    title    slug    summary
------------------------------
1     title1   slug1   summary1
2     title2   slug2   summary2
3     title3   slug3   summary3
4     title4   slug4   summary4

我正在尝试选择所有字段,同时选择上一行/下一行的id,title和slu

SELECT
    title, slug, summary, id as current_id,
    (SELECT id    FROM table WHERE id < current_id ORDER BY id DESC LIMIT 1) AS prev_id,
    (SELECT title FROM table WHERE id < current_id ORDER BY id DESC LIMIT 1) AS prev_title,
    (SELECT slug  FROM table WHERE id < current_id ORDER BY id DESC LIMIT 1) AS prev_slug,
    /*
    (SELECT id ...  ) AS next_id
    (SELECT title...) AS next_title
    ...
    and if there are more fields to select, I have to repeat this (SELECT...)
    */
FROM
    table
WHERE
    id IN (2,3,4);

查询有效,但显然这不是明智的方法。

有些人可以帮忙简化一下吗?感谢

5 个答案:

答案 0 :(得分:1)

好的,我觉得这很容易。但是在没有工作解决方案的一个小时之后,我将以我刚才想出的方式回答我自己的问题。

使用 CONCAT_WS

SELECT
    title, slug, summary, id as current_id,
    (
        SELECT
            CONCAT_WS(',' id, title, slug)
        FROM
            table
        WHERE
            id < current_id ORDER BY id DESC LIMIT 1)
    ) AS prev_data,
    (
        SELECT
            CONCAT_WS(',' id, title, slug)
        FROM
            table
        WHERE
            id > current_id ORDER BY id ASC LIMIT 1)
    ) AS next_data
FROM
    table
WHERE
    id IN (2,3,4);

,结果就像

id        => 2
title     => title2
slug      => slug2
summary   => summary2
prev_data => 1,title1,slug1
next_data => 3,title3,slug3

然后我必须explode(PHP)prev_datanext_data来获取详细信息。

我仍然在寻找一种(更好)的方法来仅使用MySQL。

答案 1 :(得分:1)

假设 Id列为auto_increment 且值id之间没有差距(意味着它们是增加为1,2,3,4。在1,3和4之间没有间隙,那么你可以试试这个:

SELECT T.Id AS CurrentId
    , T.Title AS CurrentTitle
    , T.Slug AS CurrentSlug
    , T.Summary AS CurrentSummary
    , IFNULL(P.Id, -1) AS PreviousId
    , IFNULL(P.Title, '') AS PreviousTitle
    , IFNULL(P.Slug, '') AS PreviousSlug
    , IFNULL(P.Summary, '') AS PreviousSummary
    , IFNULL(N.Id, -1) AS NextId
    , IFNULL(N.Title, '') AS NextTitle
    , IFNULL(N.Slug, '') AS NextSlug
    , IFNULL(N.Summary, '') AS NextSummary
    FROM table T
    LEFT JOIN table P ON P.Id - 1 = T.Id
    LEFT JOIN table N ON N.Id + 1 = T.Id
    WHERE T.Id IN (2, 3, 4);

否则,您发布的答案是正确的。

答案 2 :(得分:0)

您可以从一个子查询中提取列:

SELECT
    title, slug, summary, id as current_id, prev.prev_id, prev.prev_title, prev.prev_slug, next.next_id, next.next_title, next.next_slug
FROM
    table,
    (SELECT id AS prev_id, title AS prev_title, slug AS prev_slug FROM table WHERE id < 2 ORDER BY id DESC LIMIT 1) AS prev,
    (SELECT id AS next_id, title AS next_title, slug AS next_slug FROM table WHERE id > 2 ORDER BY id DESC LIMIT 1) AS next
WHERE
    id = 2;

但是如果你必须在你的位置使用IN条款,这将无效;您需要为id ...

的每个值运行此查询

答案 3 :(得分:0)

也许这样的事情会起作用。我没有测试它所以我不确定,但看起来不错:)

SELECT
  current.title as current_title,
  current.slug as current_slug,
  current.summary as current_summary, 
  current.id as current_id,
  prev.title as prev_title,
  prev.slug as prev_slug,
  prev.summary as prev_summary,
  prev.id as prev_id,
  next.title as next_title,
  next.slug as next_slug,
  next.summary as next_summary,
  nexrt.id as next_id
FROM
  `table` current LEFT JOIN 
  `table` prev ON prev.id = current.id - 1 LEFT JOIN
  `table` next ON next.id = current.id + 1                    
WHERE
  current.id IN (2,3,4)

答案 4 :(得分:0)

很抱歉给您一个6岁的小问题,但必须这样做:)
LAG()LEAD()来营救!
非常方便,也可以在Oracle和SQL Server中使用:

select 
    title, lead (title) over (order by id) next_title, lag (title) over (order by id) prev_title,
    slug, lead (slug) over (order by id) next_slug, lag (slug) over (order by id) prev_slug,
    summary, lead (summary) over (order by id) next_summary, lag (summary) over (order by id) prev_summary,
    id, lead (id) over (order by id) next_id, lag (id) over (order by id) prev_id
from `table`
;
/*
create table `table` as
(select id, concat('title', id) title, concat('slug', id) slug, concat('summary', id) summary
from
(select 1 id union all
select 14 id union all
select 34 id union all
select 13 id union all
select 2 id union all
select 4 id ) as q)
*/