Mysql两个选择与订单联合的状态

时间:2017-04-28 14:14:15

标签: mysql sql-order-by union

我正在尝试根据搜索者的输入进行查询以获取数据库中的产品。将搜索者输入的单词设置为“堆栈溢出”。

查询如下:

SELECT * FROM 
(SELECT * FROM products t1 
INNER JOIN products_references t2 ON t1.id = t2.id 
INNER JOIN products_photo t3 ON t2.id = t3.id 
WHERE  
        (t2.name LIKE '%stack%' COLLATE UTF8_UNICODE_CI
        OR t3.photo_name LIKE '%stack%' COLLATE UTF8_UNICODE_CI
        ) 
    AND
        (
        t2.name LIKE '%overflow%' COLLATE UTF8_UNICODE_CI
        OR t3.photo_name LIKE '%overflow%' COLLATE UTF8_UNICODE_CI
        )

ORDER BY 
CASE WHEN (t2.name LIKE '%stack%') THEN 0 ELSE 1 END, 
CASE WHEN (t3.photo_name LIKE '%stack%' OR t3.photo_name LIKE '%overflow%' ) THEN 0 ELSE 1 END
) as a 
UNION DISTINCT
SELECT * FROM 
(SELECT * FROM products t1 
INNER JOIN products_references t2 ON t1.id = t2.id 
INNER JOIN products_photo t3 ON t2.id = t3.id 
WHERE  
        (t2.name LIKE '%stack%' COLLATE UTF8_UNICODE_CI
        OR t3.photo_name LIKE '%stack%' COLLATE UTF8_UNICODE_CI
        ) 
ORDER BY 
CASE WHEN (t2.name LIKE '%stack%' ) THEN 0 ELSE 1 END, 
CASE WHEN (t3.photo_name LIKE '%stack%' ) THEN 0 ELSE 1 END
) as b LIMIT 0,10

我要存档的内容:

  • 获取第一个查询的结果,然后获取第二个查询的结果,按照每个查询的自己的规则排序。
  • 删除已在第一个查询中显示的已重复行。

示例:

表A结果

  • 堆栈溢出mysql
  • stack overflow jquery

表B结果

  • 堆叠的东西
  • stack overflow jquery
  • 叠加所有

最终结果

  • 堆栈溢出mysql
  • stack overflow jquery
  • 堆栈溢出
  • 叠加所有

我现在得到的结果是没有按我的要求排序。有什么想法吗?

修改

我尝试过spencer7593解决方案:

SELECT *
FROM products t1 
JOIN products_references t2 ON t1.id = t2.id 
JOIN products_photo t3 ON t2.id = t3.id 
WHERE t2.name       LIKE '%stack%' COLLATE UTF8_UNICODE_CI 
  OR t3.photo_name LIKE '%stack%' COLLATE UTF8_UNICODE_CI
ORDER
  BY CASE WHEN (t2.name       LIKE '%stack%' ) THEN 0 ELSE 1 END,
  CASE WHEN (t3.photo_name LIKE '%stack%' OR t3.photo_name LIKE '%overflow%' ) THEN 0 ELSE 1 END,
  CASE WHEN (t3.photo_name LIKE '%stack%' ) THEN 0 ELSE 1 END

这里的主要问题是两个查询按第一个单词排序(上例中的'%stack%')。由于第一个查询在某种程度上是第二个的子集,因此一起排序会改变顺序。如何加入这两个查询以保持给定的相同顺序,因为它们是单独的查询?

1 个答案:

答案 0 :(得分:1)

当外部查询中没有ORDER BY时,MySQL会优化内联视图中的ORDER BY子句。 (如果视图查询包含LIMIT子句,则内联视图中的ORDER BY子句不会被优化;但是不保证外部查询返回的行的顺序。)

如果要按特定顺序返回行,请在最外面的查询中添加ORDER BY。

参考:https://dev.mysql.com/doc/refman/5.7/en/union.html

  

对单个SELECT语句使用ORDER BY并不意味着行在最终结果中出现的顺序,因为UNION默认生成一组无序行。因此,在此上下文中使用ORDER BY通常与LIMIT结合使用,因此它用于确定要为SELECT检索的所选行的子集,即使它不一定影响这些行的顺序。最终的UNION结果。如果在SELECT中没有LIMIT出现ORDER BY,它会被优化掉,因为它无论如何都没有效果。

     

要使用ORDER BY或LIMIT子句对整个UNION结果进行排序或限制,请为各个SELECT语句加上括号,并将ORDER BY或LIMIT置于最后一个之后。

就外部查询中的行排序而言,我们可以包含一个“discriminator列”,它告诉我们哪个查询返回了一行。在此示例中,我们在第一个查询返回的行上返回文字值“1”,在第二个查询返回的行上返回文字值“2”:

 ( SELECT '1' AS src, f.* FROM ... ORDER BY ... )
 UNION ALL
 ( SELECT '2' AS src, s.* FROM ... ORDER BY ... )
 ORDER BY src, ...

但是使用这些不同的值,我们将无法使用DISTINCT删除重复项,或者优先保留第一个查询中的行。

<强>后续

我在联合编辑的两个查询之间看到的唯一区别是ORDER BY子句,以及WHERE子句的这一部分

AND
    (
    t2.name LIKE '%overflow%' COLLATE UTF8_UNICODE_CI
    OR t3.photo_name LIKE '%overflow%' COLLATE UTF8_UNICODE_CI
    )

看起来第一个查询返回第二个返回的行的子集。

所以,我不明白为什么这需要两个单独的查询。

我们不能只运行一个查询,其中包括第二个查询返回的行,然后返回第一个查询首先返回的行。

我们可以从WHERE子句中移动该条件,然后按顺序排序;将它作为ORDER BY子句中的第一个表达式。

  SELECT *
    FROM products t1 
    JOIN products_references t2 ON t1.id = t2.id 
    JOIN products_photo t3 ON t2.id = t3.id 
   WHERE t2.name       LIKE '%stack%' COLLATE UTF8_UNICODE_CI 
      OR t3.photo_name LIKE '%stack%' COLLATE UTF8_UNICODE_CI
   ORDER
      BY CASE WHEN (t2.name       LIKE '%overflow%' OR t3.photo_name LIKE '%overflow%') THEN 0 ELSE 1 END
       , CASE WHEN (t2.name       LIKE '%stack%'    OR t3.photo_name LIKE '%overflow%') THEN 0 ELSE 1 END
       , CASE WHEN (t3.photo_name LIKE '%stack%'    OR t3.photo_name LIKE '%overflow%') THEN 0 ELSE 1 END
       , CASE WHEN (t2.name       LIKE '%stack%'                                      ) THEN 0 ELSE 1 END
       , CASE WHEN (t3.photo_name LIKE '%stack%'                                      ) THEN 0 ELSE 1 END

ORDER BY子句中的第一个表达式仅对第一个查询返回的行计算为TRUE。

如果我们想要删除重复的行,我们可以在SELECT之后添加DISTINCT关键字,或者添加一个合适的GROUP BY子句。

并添加回所需的任何COLLATE UTF8_UNICODE_CI