12

所以,

问题

我的问题是关于 - 如何以相反的顺序将 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));

- 有关示例结构和代码,请参阅此小提琴

一些背景

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

问题

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

4

3 回答 3

2

我认为唯一需要改进的是

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 起了别名,因为我看不到小提琴中的列

于 2013-10-01T11:43:58.777 回答
1

如果没有SQL 标准 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;
于 2013-10-01T13:49:52.220 回答
0
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 列,不确定我的查询是否错误。

于 2013-10-01T11:10:24.543 回答