Mysql:如果不满足搜索条件,查询可以返回最后一个条目吗?

时间:2015-10-09 17:39:02

标签: php mysql

我有一个脚本可根据请求的日期搜索某些值。

SELECT `entry_value` FROM `data` WHERE (`entry_year` =  $year AND `entry_month` = $month) LIMIT 1;

现在,问题在于当用户输入的日期太近而没有找到任何值时,我想获取最新的可用条目。

我知道如何检索最后一个条目,我可以使用第一个调用来检查最后一个可用日期是什么,并调用上面的查询或另一个查询以获取最后一个值,如果请求的那个不可用。 但是,想知道是否有办法直接向mysql询问?我不能编写代码,因为我不知道要使用的构造类型,但理想情况下逻辑将是这样的:

SELECT `entry_value` FROM `data` 
WHERE (`entry_year` =  $year AND `entry_month` = $month) 
OR_IF_NOT_FOUND WHERE MAX(`id`) 
LIMIT 1;

在mysql中有类似的内容吗?

亲切的问候

3 个答案:

答案 0 :(得分:1)

方法1

您可以使用UNION运行查询,然后使用相同顺序的相同字段运行“默认”查询。

SELECT ...query1...
UNION
SELECT * FROM ( SELECT ... LIMIT 1 ) AS defaults;

这将始终运行第一个查询第二个查询,并且将始终返回比单独第一个查询更多的结果。然后你可以放弃最后的结果。

另一种可能性是以相反的顺序进行。现在首先返回“空”结果:

SELECT * FROM ( SELECT ... LIMIT 1 ) AS defaults;
UNION
SELECT ...query1...

这样你就可以提取一个元组,然后就像你单独运行第一个查询一样继续。

方法2

在某些情况下,您可以使用结果建立首选项订单。例如:

SELECT `entry_value` FROM `data` WHERE (`entry_year` = $year AND
`entry_month` = $month) LIMIT 1;

可能会成为:

SELECT `entry_value` FROM `data` ORDER BY 
    (`entry_year` = $year AND `entry_month` = $month) DESC,
    `entry_year` = $year DESC,
    ABS(`entry_year` - $year)*12 + ABS(`entry_month` - $month)
LIMIT 1;

这将检索所有数据,(entry_year = $year AND entry_month = $month)可以是true(1)或false(0)。 DESC命令将使第一行成为完美匹配的那一行。

同样,在不匹配的行中,如果存在,则会选择随右年份随机排列的行。但如果所需年份根本没有数据存在,那么将选择具有最小时间距离的行。

此方法强烈建议在使用的字段(年和月)上设置索引,并对所有记录执行扫描。所以它可能非常昂贵。

方法3

在性能方面,方法1几乎与运行两个查询相同,所以如果可能的话,你宁愿明确地执行它,例如:

// CODE BEFORE MODIFICATION (ran 1 query)
$query = "SELECT...";
// Execute query

foreach ($tuple = SQLFetch($handle)) {
     // ...do something with data
}



// CODE AFTER (2 queries - or any number, actually)

$queries = [                   
    "SELECT ...",
    "SELECT ... LIMIT 1",
];
foreach ($queries as $query) { 
    // $query = 
    // Execute $query
    foreach ($tuple = SQLFetch($handle)) {
        // ...do something with data
    }
    if (SQLNumRows($handle) > 0) {
        break;
    }
}

正如您所看到的,旧代码实际上保持不变,只有在它之前的查询没有返回任何内容时才会执行额外的查询(或查询)。获取元组和检索元组计数的实际指令取决于您正在使用的实际数据库接口。

答案 1 :(得分:0)

http://sqlfiddle.com/#!9/437374/5

SELECT 
  COALESCE(d1.id,d.id) id, 
  COALESCE(d1.entry_value,d.entry_value) entry_value 
FROM `data` d
LEFT JOIN `data` d1
ON d1.entry_year =  $year
  AND d1.entry_month = $month 
ORDER BY d.id DESC
LIMIT 1;

答案 2 :(得分:0)

我认为这可能适合你:

 SELECT `entry_value` FROM `data` WHERE 
 (`entry_year` =  $year AND `entry_month` = $month) 
 OR 
 (`entry_year` =  $most_recent_year AND `entry_month` = $most_recent_month) 
 LIMIT 1;