2

考虑下表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 前几天_date的查询。x倒数时,_dayswithtrading_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.ini 中的变量。

4

5 回答 5

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();
于 2012-08-30T15:43:20.153 回答
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;
于 2012-08-30T15:42:39.140 回答
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

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

于 2012-08-30T15:46:02.760 回答
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 中选择每个日期,然后运行一个子查询来选择每个日期减去非交易日的日期,然后按降序对它们进行排序(最近的在前)。它将每个日期连接到它之前的每个日期,但是我们然后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子句,它将删除任何不是交易日的日期,按日期降序排列结果,然后选择第一个- 那应该是你想要的日期。试试看。

于 2012-08-30T15:59:47.707 回答
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 以及封闭选择中的 where 子句(如果它在将来)。

于 2012-08-30T15:50:56.217 回答