基于多个OR谓词的订单结果集

时间:2018-08-10 17:20:37

标签: mysql sql

我遇到一种情况,我需要根据具有优先顺序的一组设置标准从表中获取X条记录。换句话说:

  1. 尝试使用条件1从表中获取X条记录。
  2. 如果不满足X的配额,请尝试使用条件2从表中获取其他记录。
  3. 如果未达到X STILL的配额,请尝试使用条件3从表中获取其他记录。

一个具体示例:

+----+-----------------+-------------------+-------------+                     
| id | primary_user_id | secondary_user_id | location_id |
+----+-----------------+-------------------+-------------+
|  1 | user1           | user1             | MI          |
|  2 | user1           | user2             | NV          |
|  3 | user2           | user1             | MI          |
|  4 | user1           | user3             | MI          |
|  5 | user4           | user5             | NV          |
+----+-----------------+-------------------+-------------+
  • 条件1:secondary_user_id = @user
  • 条件2:primary_user_id = @user
  • 条件3:location_id = @location

根据我的理解,简单的OR子句不能保证返回的记录与获取记录的标准顺序相同:

SELECT * FROM Foo WHERE
  secondary_user_id = 'user1' OR
  primary_user_id = 'user1' OR
  location_id = 'NV'
LIMIT 2

UNION似乎是一个更好的选择:

SELECT * FROM Foo WHERE secondary_user_id = 'user1'
UNION
SELECT * From Foo WHERE primary_user_id = 'user1'
UNION
SELECT * FROM Foo WHERE location_id = 'NV'

有限制:

SELECT * FROM (
  SELECT * FROM Foo WHERE secondary_user_id = 'user1'
  UNION
  SELECT * From Foo WHERE primary_user_id = 'user1'
  UNION
  SELECT * FROM Foo WHERE location_id = 'NV'
) AS r LIMIT 2

如果要确保结果与获取标准时的顺序相同,UNION是这里的唯一选择吗?我知道可以在我的应用程序中以编程方式完成此操作,但是我想尽可能地将很多工作分担给数据库(如果重要的话,可以使用MySQL)。

3 个答案:

答案 0 :(得分:0)

由于您希望将其保留在MySQL中,因此您的上一个查询看起来是该任务的最佳工作解决方案。

唯一的问题是UNION子句可能会多次给您一些行。例如,如果某行包含secondary_user_id = 'user1'primary_user_id = 'user1',则它将返回两次。

为避免这种情况,请使用DISTINCT

SELECT DISTINCT * FROM (
  SELECT * FROM Foo WHERE secondary_user_id = 'user1'
  UNION
  SELECT * From Foo WHERE primary_user_id = 'user1'
  UNION
  SELECT * FROM Foo WHERE location_id = 'NV'
) AS r LIMIT 2

已编辑

@ZaynulAbadinTuhin完全正确

  

UNION如果两个查询返回相同的名称,则会自动生成DISTINCT

因此,从该问题进行的最后一个查询无需任何更改即可正常工作。

答案 1 :(得分:0)

您还可以简单地使用OR,然后使用CASE添加ORDER BY:

SELECT * 
  FROM Foo 
 WHERE secondary_user_id = 'user1' 
    OR primary_user_id = 'user1' 
    OR location_id = 'NV'
 ORDER BY (CASE
               WHEN secondary_user_id = 'user1' THEN 0
               ELSE 100
           END) +
          (CASE
               WHEN primary_user_id = 'user1' THEN 0
               ELSE 10
           END) +
          (CASE
               WHEN location_id = 'NV' THEN 0
               ELSE 1
           END);

这是有效的,但可读性较差。

答案 2 :(得分:0)

只需使用order by

SELECT *
FROM Foo
WHERE secondary_user_id = 'user1' OR
      primary_user_id = 'user1' OR
      location_id = 'NV'
ORDER BY (CASE WHEN secondary_user_id = 'user1' THEN 1
               WHEN primary_user_id = 'user1' THEN 2
               ELSE 3
          END)
LIMIT 2;

请勿重复,我重复请勿,并假设UNIONUNION ALL将按特定顺序产生结果。保证排序的唯一方法是使用显式的ORDER BY子句。