【问题标题】:Simplifing MySQL nested SELECT简化 MySQL 嵌套 SELECT
【发布时间】:2012-11-16 09:54:24
【问题描述】:
id title slug 摘要
------------------------------
1 标题1 slug1 摘要1
2 标题2 slug2 摘要2
3 标题3 slug3 摘要3
4 标题4 slug4 摘要4

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

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

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

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

【问题讨论】:

  • 在 SQL 中有更好的方法 - 只是没有 MySQL 的有限 SQL 功能。
  • 我们渴望向您学习。

标签: mysql select nested


【解决方案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 标题 => 标题2 蛞蝓=>蛞蝓2 摘要 => 摘要2 prev_data => 1,title1,slug1 next_data => 3,title3,slug3

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

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

【讨论】:

    【解决方案2】:

    假设Id 列是auto_increment 并且值id 之间没有间隙(意味着它们递增为 1、2、 3, 4. 1, 3, 4, 6) 之间没有间隙,那么你可以试试这个:

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

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

    【讨论】:

    • 谢谢凯尔。 id 列 auto_increment,但不能保证没有间隙,因为条目会不时删除。这就是为什么我必须使用 > 和 <.>
    • 我明白了。只是一个想法,如果您碰巧使用任何服务器端语言 [C#Java 等],也许您可​​以尝试在代码中获取 previousnext 记录,而不是在查询中。只是考虑平衡执行时间。
    【解决方案3】:

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

    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;
    

    但是,如果您必须在 where 中使用 IN 子句,这将不起作用;您需要为 id 的每个值运行此查询...

    【讨论】:

    • 太糟糕了,我一次获取多行......我认为这很容易
    【解决方案4】:

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

    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)
    

    【讨论】:

      【解决方案5】:

      抱歉,我对一个 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)
      */
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-11
        • 2012-09-13
        • 1970-01-01
        • 2015-01-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多