5

我有一个表,我想根据优先级和日期来获取记录,我通过这个查询得到

  SELECT * 
    FROM tbadv 
   WHERE advstrdat < CURDATE() 
ORDER BY advenddat DESC,
         advpri=1 DESC,
         advpri=2 DESC,
         advpri=3 DESC,
         advpri=4 DESC,
         advpri=5 DESC 
   LIMIT 1

但是如果存在多个具有相同优先级的记录,那么我想从中随机记录。

告诉我我更喜欢哪个ORDER BY RAND()或使用JOIN.

这些是我的表的列:

advid
advtit
advdes
advimg
advurl
advloc
advstrdat
advenddat
advpri

任何帮助,建议将不胜感激。

4

2 回答 2

4

目前还不太清楚你想如何解决关系。

反正:

SELECT * 
   FROM tbadv 
   WHERE advstrdat < CURDATE() 
ORDER BY advenddat DESC, advpri BETWEEN 1 AND 5 DESC, advpri DESC, RAND()
   LIMIT 1

这将根据日期检索最新的记录advenddat,而不考虑优先级,即比高优先级记录更新的低优先级记录将首先出现(因此,检查这advenddat是一个日期而不是日期时间,或者,如果它是,它是用date初始化的。否则你只会很少有相同的记录advenddat,要根据其他字段进行排序)。

然后将选择优先级在 1 到 5 之间的那些记录。其中,优先级高的优先。

如果两条记录在 1 和 5 之间有相同advenddat的和相同的advpri(比如 3),那么平局将被随机打破。

出于性能原因,您将希望按advstrdat, advenddat, advpri以下顺序设置覆盖索引:

CREATE UNIQUE INDEX tbadv_ndx ON tbadv ( advstrdat, advenddat, advpri, advid );

如果表很大,并且匹配了许多记录,则可以通过将记录选择(只需要主键)和实际记录检索解耦来实现最佳性能:

SELECT tbadv.*
    FROM tbadv
    JOIN ( 
        SELECT advid
            FROM tbadv
            WHERE advstrdat < CURDATE()
           ORDER BY advenddat DESC, advpri BETWEEN 1 AND 5 DESC, advpri DESC, RAND()
        LIMIT 1 ) AS p
    USING ( advid );

+----+-------------+------------+--------+---------------+-----------+---------+-------+-------+-----------------------------------------------------------+
| id | select_type | table      | type   | possible_keys | key       | key_len | ref   | rows  | Extra                                                     |
+----+-------------+------------+--------+---------------+-----------+---------+-------+-------+-----------------------------------------------------------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL      | NULL    | NULL  |     1 |                                                           |
|  1 | PRIMARY     | tbadv      | const  | PRIMARY       | PRIMARY   | 4       | const |     1 |                                                           |
|  2 | DERIVED     | tbadv      | range  | tbadv_ndx     | tbadv_ndx | 4       | NULL  | 60924 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+------------+--------+---------------+-----------+---------+-------+-------+-----------------------------------------------------------+

上面是一个包含大约 13 万行的示例表,非常不平衡(所有记录都有 valid curdate,所有记录都有 validpriority等)。然而,它在几毫秒内完成。

“无效”记录被快速过滤,因此性能等同于单个查询,除了只advid检索:这里只有七个记录匹配:

+----+-------------+------------+--------+---------------+-----------+---------+-------+------+-----------------------------------------------------------+
| id | select_type | table      | type   | possible_keys | key       | key_len | ref   | rows | Extra                                                     |
+----+-------------+------------+--------+---------------+-----------+---------+-------+------+-----------------------------------------------------------+
|  1 | PRIMARY     | <derived2> | system | NULL          | NULL      | NULL    | NULL  |    1 |                                                           |
|  1 | PRIMARY     | tbadv      | const  | PRIMARY       | PRIMARY   | 4       | const |    1 |                                                           |
|  2 | DERIVED     | tbadv      | range  | tbadv_ndx     | tbadv_ndx | 4       | NULL  |    7 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+------------+--------+---------------+-----------+---------+-------+------+-----------------------------------------------------------+

不同的顺序

如果你想advpri优先于advenddat,即今天到期的优先级为 5 的记录必须优先于优先级为 4 的记录,即使它明年到期,你只需要反转advpriand的位置advenddat

ORDER BY advpri BETWEEN 1 AND 5 DESC, advpri DESC, advenddat DESC, RAND()

现在优先级 1-5 优先,然后是优先级 0、6、7 和 1-5 范围之外的其他优先级;他们首先获得最高优先级(即5)。如果两条记录具有相同的优先级,则预期寿命较长的记录优先。只有当预期寿命相同时,选择是随机的。(您还必须在索引创建语句中交换字段位置)。

于 2013-07-25T14:03:59.993 回答
0
SELECT * FROM tbadv where advstrdat<curdate() ORDER BY advenddat DESC, advpri DESC, RAND() DESC LIMIT 1
于 2013-07-22T11:21:30.960 回答