从数据库x天开始选择过去的日期

时间:2012-08-30 15:37:10

标签: php mysql

考虑下表daterange

_date        trading_day
------------------------
2011-08-01   1
2011-07-31   0
2011-07-30   0
2011-07-29   1
2011-07-28   1
2011-07-27   1
2011-07-26   1
2011-07-25   1
2011-07-24   0
2011-07-23   0
2011-07-22   1
2011-07-21   1
2011-07-20   1
2011-07-19   1
2011-07-18   1
2011-07-17   0

我需要一个在给定的_date之前返回_datex天的查询。倒计时时,_daystrading_day = 0应该被忽略。几个例子:

input                    | output
-------------------------+------------
1 day  before 2011-07-19 | 2011-07-18
2 days before 2011-08-01 | 2011-07-28 (trading_day = 0 don't count)
3 days before 2011-07-29 | 2001-07-26

第一个很简单:

SELECT _date 
FROM daterange 
WHERE trading_day = 0 AND _date < '2011-07-19' LIMIT 1

但我不知道如何查询其他示例。你呢?我倾向于一个适用于所有情况的解决方案,所以我可以在PHP中向后变换一个变量。

5 个答案:

答案 0 :(得分:3)

查询1

SELECT `_date`
FROM `daterange` 
WHERE `trading_day` = '1' AND `_date` <= '2011-07-19' 
ORDER BY `_date` DESC 
LIMIT 1 
OFFSET 1;

查询2

SELECT `_date` 
FROM `daterange` 
WHERE `trading_day` = '1' AND `_date` <= '2011-08-01' 
ORDER BY `_date` DESC 
LIMIT 1 
OFFSET 2;

查询3

SELECT `_date`
FROM `daterange` 
WHERE `trading_day` = '1' AND `_date` <= '2011-07-29' 
ORDER BY `_date` DESC 
LIMIT 1 
OFFSET 3;

准备好的声明(PDO示例)

$stmt = $dbh->prepare("SELECT `_date`
    FROM `daterange` 
    WHERE `trading_day` = '1' AND `_date` <= :given_date
    ORDER BY `_date` DESC 
    LIMIT 1 
    OFFSET :days_before");
$stmt->bindParam(':given_date', $given_date);
$stmt->bindParam(':days_before', $days_before);
$stmt->execute();

答案 1 :(得分:1)

SELECT DATE(_date - INTERVAL trading_day DAY) FROM daterange;

当交易日为0并且只返回日期时,此查询将忽略。如果您想排除没有交易日的日期,那么您需要:

SELECT DATE(_date - INTERVAL trading_day DAY) FROM daterange WHERE trading_day!=0;

如果您的日期字段已经是格式2012-01-01,则此处也不需要DATE()。如果您的日期字段是时间戳(2012-01-01 10:01:17),则DATE()将仅返回日期部分(2012-01-01)。客栈换句话说,根据你所呈现的内容,这对你也同样适用:

SELECT _date - INTERVAL trading_day DAY FROM daterange;

因此

SELECT _date - INTERVAL trading_day DAY FROM daterange WHERE trading_day!=0;

答案 2 :(得分:1)

您的第一个示例现在只是意外运行:)您需要对结果集应用订单,以确保检索2011-07-19之前的最大日期,而不仅仅是任意日期。

SELECT _date
FROM daterange
WHERE trading_day <> 0 AND _date < '2011-07-19'
ORDER BY _date DESC
LIMIT 1

如果您想要的不是某一天之前的第一天,而是某一天,那么也会在您的查询中应用OFFSET。

这个将为您提供#3所需的内容:

SELECT _date
FROM daterange
WHERE trading_day <> 0 AND _date < '2011-07-29'
ORDER BY _date DESC

LIMIT 1
OFFSET 2

OFFSET 2指示MySQL跳过本应返回的前两个结果,并从第三个结果开始。

答案 3 :(得分:1)

我对你的问题并不完全清楚 - 但似乎你想要选择之前的交易日期,以及多少天以前。我不确定你是否想对表格中的所有日期或任何单一日期这样做。

我假设它适用于表格中的所有日期,因为否则这是一个非常简单的查询。

SELECT 
dr._date as the_date, 
d2._date as previous_trading_date, 
DATEDIFF(dr._date, d2._date) days_ago

FROM daterange dr
JOIN (
    SELECT _date FROM daterange
    WHERE trading_day > 0
    ORDER BY _date DESC
) d2 ON d2._date < dr._date

GROUP BY dr._date
ORDER BY dr._date DESC

此查询的作用是从日期范围中选择每个日期,然后运行子查询以选择每个日期减去非交易日的日期,并按降序排序(最近的第一个)。它将每个日期连接到它之前的每个日期,但我们然后按daterange._date分组才能获得第一行(这将是交易日的第一个日期,因为我们做了子日期 - 与订单条款一起选择)。然后,我们使用DATEDIFF()函数计算日期和上一个交易日期之间的天数。


因此,如果您要选择之前的日期,该日期是指定日期($x)之前的某些数字($date),并忽略具有trading_day值的日期0,你会这样做:

SELECT _date

FROM daterange

WHERE _date < '{$date}'
AND trading_day > 0

ORDER BY _date DESC
LIMIT 1
OFFSET {$x - 1}

OFFSET子句允许您跳过与{$x - 1}条款匹配的前WHERE天,这些条款应该会到达您想要的日期。这个查询做了一些假设。主要是每天daterange上有一行(且只有一行)。如果你不这样做,那么你最终会得到一些意想不到的结果。

但在考虑之后,你可以做类似这样的查询:

SELECT _date

FROM daterange

WHERE _date <= DATE_SUB('2011-08-01', INTERVAL {$x} DAY)
AND trading_day > 0

ORDER BY _date DESC
LIMIT 1

此查询执行日期减法,因此您将返回{$x}天之前的日期,但通过添加trading_day > 0子句,它将删除任何非交易日的日期,按降序日期顺序排列结果,然后选择第一个 - 应该是您想要的日期。尝试一下。

答案 4 :(得分:0)

Select temp._date 
FROM (Select _date FROM daterange WHERE trading_day<>0 AND trading_day < $date ORDER BY _date) as temp
ORDER BY _date LIMIT $days_before;

只获得第一张唱片。

您也可以将ORDER BY更改为DESC,并将封闭的select中的where子句更改为将来。