将两个查询合并为一个并重新排序
但是,由于第二个查询是在第一个查询的循环中运行的,因此我无法对第一个查询返回的结果重新排序。将两个查询合并为一个并重新排序
第一个查询总是返回结果,第二个查询 - 有时候,但是当它需要时,我需要这些结果在最上面。默认情况下,结果按距离排序,从最近开始。
例如,这里就是我现在得到:
- 名1(PHONE1) - 0.1英里
- 名称2(PHONE2) - 0.4英里
- NAME3(电话3) - 1.3英里< - 现在打开(查询2匹配)
- NAME4(PHONE4) - 2.4英里
我想看到什么:
- NAME3(电话3) - 1.3英里< - 现在打开(查询2匹配)
- 名1(PHONE1) - 0.1英里
- 名称2(PHONE2) - 0.4英里
- NAME4(PHONE4) - 2.4 MI
这里是我当前的查询(简体):
查询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个查询。理想情况下,我只想做一次。
对不起,这可能很明显,但我卡住了。
不知道是否真的有效,但你可以试试下面的办法: 使用您的查询1的子查询中FROM
-clause(添加内部排序和限制),请在SELECT
-clause规则数。通过计数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
但实际上,我不会给,我可能会与您现有的个人不太复杂的查询和做法坚持之后在应用程序中重新排序。
我目前的方法存在的问题是,我无法排序第二个查询找到的匹配位于顶部的结果。我现在拥有的是由第一个查询找到的匹配列表,按照邻近性排序,如果其中一个匹配的是第二个匹配,我就以不同的方式进行设计。 – santa
但你可以在你的应用程序中进行排序。不知道你在使用什么语言/技术,但我想你可以从数组(或其他)读取query1的结果,将查询2的结果添加到相同的数据结构中,然后对其进行排序。 –
你的意思是说,使用这两个查询来构建一个数组,然后对其进行排序?我已经考虑过这种可能性,但在我走上这条路之前,我想确保我给MySQL一个公平的动摇。它返回10个结果我目前必须运行10个查询。理想情况下,我只想做一次。 – santa
,你可以使用这种方法:
select name, phone from (
select 0 order, name, phone
from ...
union all
select 1, name, phone
from ...
)q
order by q.order
感谢您的解决方案!我不确定我的邻近参数在哪里? – santa
您可以直接提供,如果您有关系数据库的连接(包括你的每一个表之间的连接即直接或间接)。
让你查询简化成一个象下面这样:只有
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
关键字时,你限制你的数据被显示。
假设:T3不包含列APIid(询问2问题 “t3.APIid” 应改为 “t2.APIid”)。
因为您的不包括在选择子句中的列排序则需要执行次数计算既可以作为衍生的表,或作为相关子查询。
派生表
在这里,您执行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 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()
调整,以满足您的需要限制。
选择的名字,从电话( 选择ROW_NUMBER()以上(按姓名顺序,手机)的顺序,姓名,电话 从... UNION ALL 从中选择1,姓名,电话 ... )● 为了通过q.order
使用ROW_NUMBER()OVER(ORDER BY姓名,电话),您可以分区和顺序递增和下降的产生和身份模拟,然后你可以加入工会或做你想做的。 (你可以做第二次选择在第一个查询的字段中选择一个,(从d
我不明白你所期望的输出选择c其中D.A = C.A B)。
对不起,我的英语:)
什么是你的表结构?和他们的关系? – nacho
@nacho我添加了表格结构。所有关系都在OP中。 – santa
你应该更精确地解释你想要订购结果的方式。按距离ASC,numberOfRules DESC? –