【问题标题】:Reverse join in MySQLMySQL中的反向连接
【发布时间】:2013-10-07 12:02:59
【问题描述】:

所以,

问题

我的问题是关于 - 如何以相反的顺序将 MySQL 中的表与自身连接起来?假设我有:

身份证名称 1 第一 2 秒 5 第三 6 第四 7 第五 8 第六 9 第七 13 八 14 九 15 第十

-现在我想创建一个查询,它将以相反的顺序返回连接的记录:

left_id 名称 right_id 名称 1 前 15 第十 2 秒 14 九 5 第三 13 八 6 第四 9 第七 7 第五 8 第六 8 第六 7 第五 9 第七 6 第四 13 八 5 第三 14 九 2 秒 15 第十 1 第一

我的方法

我现在有这个查询:

SELECT 
  l.id AS left_id, 
  l.name, 
  (SELECT COUNT(1) FROM sequences WHERE id<=left_id) AS left_order, 
  r.id AS right_id,
  r.name,
  (SELECT COUNT(1) FROM sequences WHERE id<=right_id) AS right_order 
FROM 
  sequences AS l 
  LEFT JOIN 
    sequences AS r ON 1
HAVING
  left_order+right_order=(1+(SELECT COUNT(1) FROM sequences));

-查看此fiddle 以获取示例结构和代码。

一些背景

没有用例。我以前在应用程序中这样做过。现在主要是好奇是否有办法在 SQL 中做到这一点——这就是为什么我不仅在寻找“任何解决方案”(比如我的)——而是尽可能简单的解决方案。源表总是很小(

问题

可以以某种方式简化我的查询吗?此外,重要的是不要使用变量。订单可以包含在结果中(就像我的小提琴一样)——但这不是强制性的。

【问题讨论】:

  • 当我们在思考时——你能提供一个用例吗?很好奇
  • 我猜你会仅限于 MySQL?否则使用窗口函数会很容易。
  • @a_horse_with_no_name 实际上,我受限于SQL 本身(在理想情况下,查询应该在 Postgres 和 MySQL 中工作) - 所以我认为最好的方法是避免与 DBMS 相关的功能
  • 窗口函数是 ANSI 标准,并没有使它们成为“特定于 DBMS”(实际上 MySQL 是唯一没有它们的主要 DBMS)。
  • 嗯,不知道。好吧,既然应该使用 MySQL - 我不能使用它们(以及为什么我也想避免使用 MySQL 变量)。最好的解决方案可能是 - 在应用程序中执行此操作(100% SQL-portable :p) - 但我对 SQL 解决方案感到好奇

标签: mysql sql join sql-order-by


【解决方案1】:

我认为唯一需要改进的是

SELECT 
  l.id AS left_id, 
  l.name ln, 
  (SELECT COUNT(1) FROM sequences WHERE id<=left_id) AS left_order, 
  r.id AS right_id,
  r.name rn,
  (SELECT COUNT(1) FROM sequences WHERE id>=right_id) AS right_order 
FROM 
  sequences AS l 
  LEFT JOIN 
    sequences AS r ON 1
HAVING
  left_order=right_order;

有 2 处更改应该会加快速度:

1) 首先逆序计算正确的顺序

2) 避免在最后一行使用SELECT COUNT

编辑:我给 ln,rn 起了别名,因为我看不到小提琴中的列

【讨论】:

    【解决方案2】:

    没有SQL standard RANK() OVER(...),您必须自己计算您发现的顺序。

    一行的 RANK() 只是 1 + 所有排名较高的行的 COUNT()。 (为了比较,DENSE_RANK() 是 1 + 所有 DISTINCT 更好排名的 COUNT()。)虽然 RANK() 可以作为 SELECT 投影中的标量子查询来计算——例如,你已经用 SELECT (SELECT COUNT(1) ...), ... 完成了——我更喜欢加入:

        SELECT lft.id AS "left_id", lft.name AS "left_name",
               rgt.id AS "right_id", rgt.name AS "right_name"
          FROM (   SELECT s.id, s.name, COUNT(1) AS "rank"     -- Left ranking
                     FROM sequences s
                LEFT JOIN sequences d ON s.id <= d.id
                 GROUP BY 1, 2) lft
    INNER JOIN (   SELECT s.id, s.name, COUNT(1) AS "rank"     -- Right ranking
                     FROM sequences s
                LEFT JOIN sequences d ON s.id >= d.id
                 GROUP BY 1, 2) rgt
               ON lft.rank = rgt.rank
      ORDER BY lft.id ASC;
    

    【讨论】:

    • 这对JOIN 也很好看(实际上,我更喜欢JOIN 而不是子查询)
    【解决方案3】:
    SET @rank1=0;
    SET @rank2=0;
    
    SELECT *
    FROM (SELECT *, @rank1 := @rank1 + 1 AS row_number FROM sequences ORDER BY ID ASC) t1
    INNER JOIN (SELECT *, @rank2 := @rank2 + 1 AS row_number FROM sequences ORDER BY ID DESC) t2
    on t1.row_number = t2.row_number
    

    由于某种原因,sql fiddler 确实只显示了 3 列,不确定我的查询是否错误。

    【讨论】:

    • 我不想使用变量(由于可移植性的原因)——所以这不是我想要的
    猜你喜欢
    • 2017-06-19
    • 2014-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-20
    相关资源
    最近更新 更多