将两个查询合并为一个并重新排序

时间:2017-06-12 18:00:40

标签: mysql

我有两个查询可以自己正常工作,但是,因为第二个查询是在第一个查询的循环中运行的,所以我无法重新排序第一个查询返回的结果。

第一个查询总是返回结果,第二个查询 - 有时候,但是当它发生时,我需要将这些结果放在最前面。默认情况下,结果按距离排序,从最近的开始。

例如,这就是我现在所得到的:

  • 姓名1(电话1) - 0.1英里
  • 姓名2(电话2) - 0.4英里
  • 姓名3(电话3) - 1.3英里< - 现在打开(查询2匹配)
  • 姓名4(电话4) - 2.4英里

我想看到的内容:

  • 姓名3(电话3) - 1.3英里< - 现在打开(查询2匹配)
  • 姓名1(电话1) - 0.1英里
  • 姓名2(电话2) - 0.4英里
  • 姓名4(电话4) - 2.4英里

以下是我当前的查询(简化):

查询1:

 SELECT
     t1.busName,
     t1.busPhone
 FROM t1
 WHERE t1.lat BETWEEN $min_lat AND $max_lat
   AND t1.lon BETWEEN $min_lon AND $max_lon
 ORDER BY (POW((t1.lon-$lon),2) + POW((t1.lat-$lat),2))
 LIMIT 5

查询2:

SELECT COUNT(t3.rule_id) AS rcount
FROM t3
LEFT JOIN t2 ON (t3.rule_busID = t2.busID)
WHERE t3.APIid = '".$APIid."'

我遇到的另一个问题是无法在t1和t3之间建立直接连接。唯一的办法就是拥有t2

t1.APIid = t2.APIid
t2.busID = t3.rule_busID

表结构如下:

t1
--------------------------------------
busName | busPhone | lon | lat | APIid 

t2
--------------------------------------
busID | APIid

t3
--------------------------------------
rule_id | rule_busID 

目前,有两个查询,如果我返回10个结果,我必须运行11个查询。理想情况下,我只想做一次。

对不起,这可能很明显,但我已经卡住了。

5 个答案:

答案 0 :(得分:8)

假设:t3不包含列APIid(查询2中的“t3.APIid”应为“t2.APIid”)。

因为您按照未包含在select子句中的列进行排序,所以您需要将计数计算作为派生表或相关子查询执行。

派生表

在这里执行COUNT()&子查询中的GROUP BY,结果加入主查询。

SELECT
      t1.busName
    , t1.busPhone
    , COALESCE(r.rcount,0) rcount
FROM t1
LEFT JOIN (
      SELECT
            t2.APIid
          , COUNT(t3.rule_id) AS rcount
      FROM t3
      INNER JOIN t2 ON t3.rule_busID = t2.busID
      GROUP BY
            t2.APIid
      ) r ON t1.APIid = r.APIid
WHERE t1.lat BETWEEN $min_lat AND $max_lat
AND t1.lon BETWEEN $min_lon AND $max_lon
ORDER BY (POW((t1.lon - $lon), 2) + POW((t1.lat - $lat), 2))
#LIMIT 5
;

相关子查询

另一种方法是在主查询的select子句中执行计数计算。这种子查询样式可能会导致性能问题,但如果从主查询返回的行数不是很大,那么这种方法可能会运行得很好。

SELECT
      t1.busName
    , t1.busPhone
    , COALESCE(SELECT COUNT(t3.rule_id)
      FROM t3 INNER JOIN t2 ON t3.rule_busID = t2.busID 
      WHERE t2.APIid = t1.APIid
      ),0) as rCount
FROM t1
WHERE t1.lat BETWEEN $min_lat AND $max_lat
AND t1.lon BETWEEN $min_lon AND $max_lon
ORDER BY (POW((t1.lon - $lon), 2) + POW((t1.lat - $lat), 2))
#LIMIT 5
;

注意:在任何一种方法中,在t2上从t3使用LEFT JOIN没有任何价值。如果t3具有未链接到t2的规则,则也无法将这些规则链接到t1。所以,只需在t3和t2之间使用INNER JOIN。

如果没有匹配计数,您可能需要使用COALESCE()或IFNULL()返回零。您可以使用任一功能,但我更喜欢ANSI标准COALESCE()

根据您的需要调整LIMIT。

答案 1 :(得分:0)

不确定这是否真的有效,但您可以尝试以下方法: 在FROM - 子句中使用Query1作为子查询(添加内部排序和限制),在SELECT - 子句中选择规则计数。按计数DESC对结果进行排序。

没有测试过,但看起来应该是这样的:

SELECT
  sub1.busName,
  sub1.busPhone,
  (SELECT COUNT(t3.rule_id) AS rcount FROM t3 LEFT JOIN t2 ON (t3.rule_busID = t2.busID) WHERE t2.APIid = t1.APIid) as rCount
FROM 
  (
    SELECT
       t1.busName,
       t1.busPhone
    FROM t1
      WHERE t1.lat BETWEEN $min_lat AND $max_lat AND t1.lon BETWEEN $min_lon AND $max_lon
      ORDER BY (POW((t1.lon-$lon),2) + POW((t1.lat-$lat),2)) ASC
      LIMIT 5
  ) as sub1
ORDER BY rCount DESC

但实际上我不会这样做,我可能会坚持使用您当前的单个不太复杂的查询方法以及之后在应用程序中重新排序。

答案 2 :(得分:0)

你可以使用这种方法:

select name, phone from (
 select 0 order, name, phone
 from ...
 union all
 select 1, name, phone
 from ...
 )q
order by q.order

答案 3 :(得分:0)

如果您有关系数据库(即每个表之间的连接,包括直接或间接连接),您可以直接提供连接。

所以您的查询简化为如下所示:

SELECT t1.busName, t1.busPhone, COUNT(t3.rule_id) AS rcount FROM t1 INNER JOIN t2 on t2.APIid=t1.APIid LEFT JOIN t3 on t2.busID=t3.rule_busID WHERE t1.lat BETWEEN $min_lat AND $max_lat AND t1.lon BETWEEN $min_lon AND $max_lon AND t3.APIid = '".$APIid."' ORDER BY (POW((t1.lon-$lon),2) + POW((t1.lat-$lat),2)) LIMIT 5

仅在限制要显示的数据时使用LIMIT关键字。

答案 4 :(得分:0)

选择姓名,电话自(  选择ROW_NUMBER()(按名称,电话排序)作为订单,名称,电话  来自......  联合所有  选择1,姓名,电话  来自......  )问 按q.order排序

使用ROW_NUMBER()(按名称,电话排序)您可以对asc进行分区和下订单以及降序以进行生成和身份模拟,然后您可以联合加入或执行您想要的操作。 (你可以在第一个查询的字段中进行第二次选择,从d

中选择a,(从c中选择b,其中d.a = c.a)

我不理解你期望的输出。

对不起我的英文:)