从数组

时间:2016-11-12 00:55:48

标签: php mysql arrays loops datetime

我有以下SQL查询,该查询返回包含特定日期的贷款金融交易的结果......

$data = array( 'loan_id'=>130 );
$STH = $DBH->prepare("SELECT * FROM ledger WHERE loan_id = :loan_id");
$STH->execute($data);
$STH->setFetchMode(PDO::FETCH_ASSOC);
$row = $STH->fetchAll(); 

print_r($row);

这给出了以下结果

Array ( 
 [0] => Array ( 
        [ledger_id] => 38 
        [loan_id] => 130 
        [ledger_type_id] => 1 
        [amount] => 1.20 
        [ledger_date] => 2016-07-25 
    ) 

 [1] => Array ( 
        [ledger_id] => 39 
        [loan_id] => 130 
        [ledger_type_id] => 3 
        [amount] => 0.90 
        [ledger_date] => 2016-08-15 
    ) 

 [2] => Array ( 
        [ledger_id] => 40 
        [loan_id] => 130 
        [ledger_type_id] => 2 
        [amount] => 0.30 
        [ledger_date] => 2016-09-19 
    ) 
) 

我现在需要遍历贷款已处于活动状态的所有日期,并找到循环中当前日期发生的交易的“ledger_type_id”和“金额”。分类帐表不包含每天的记录,但是我需要查看每个单独的日子,贷款已经活动用于与此问题无关的其他目的。

$start_date = new DateTime('2016-07-13');
$today = new DateTime();
$today = $today->modify( '+1 day' ); // add one day to include today
$interval = new DateInterval('P1D'); 
$daterange = new DatePeriod($start_date, $interval ,$today);

foreach ($daterange as $date) {

    /*  
       The above SQL query returns a row with the 'ledger_date' 
       of '2016-08-15'

       I need to find the value of the ledger_type_id 
       for the same row from the above query 
       when $date = '2016-08-15' in this loop
    */

    // Do other unrelated stuff on each day of the loop.....

}

我使用in_array()尝试过一些事情,但没有成功。

1 个答案:

答案 0 :(得分:0)

当您在SQL中工作并且您认为我需要一个循环,应该让您思考,等一下。 SQL是声明性的,而不是程序性的

在SQL中,处理日期范围内每天的问题通常是使用包含所有日期的表(物理或虚拟)来完成的。我们可以称之为calendar表。然后我们可以LEFT JOIN表格中包含该表格的实际数据。在您的示例中:

SELECT calendar.day, ledger.*
  FROM calendar
  LEFT JOIN ledger ON calendar.day = ledger.date
 WHERE loan_id = :loan_id
 ORDER BY calendar.day, ledger.id

这将为每个日历日提供至少一行的结果集。

诀窍是获得一个合适的calendar表。这是一种方法。

             SELECT mintime + INTERVAL seq.seq DAY AS day
               FROM (
                       SELECT MIN(DATE(ledger.date)) AS mintime,
                              MAX(DATE(ledger.date)) AS maxtime
                         FROM ledger
                    ) AS minmax
               JOIN seq_0_to_999999 AS seq 
                 ON seq.seq < TIMESTAMPDIFF(DAY,mintime,maxtime)

这将为您提供一个虚拟表(子查询),涵盖分类帐中的日期范围。

所以你的查询将如下所示:

SELECT calendar.day, ledger.*
  FROM (
             SELECT mintime + INTERVAL seq.seq DAY AS day
               FROM (
                       SELECT MIN(DATE(ledger.date)) AS mintime,
                              MAX(DATE(ledger.date)) AS maxtime
                         FROM ledger
                    ) AS minmax
               JOIN seq_0_to_999999 AS seq 
                 ON seq.seq < TIMESTAMPDIFF(DAY,mintime,maxtime)
       ) calendar
  LEFT JOIN ledger ON ledger.date >= calendar.day
                  AND ledger.date < calendar.day + INTERVAL 1 DAY
 WHERE loan_id = :loan_id
 ORDER BY calendar.day, ledger.id

如果您正在使用MySQL的MariaDB fork,则为sequence table预定义便捷表seq_0_to_999999。否则,您可以轻松地将其创建为一系列视图,如下所示:

DROP TABLE IF EXISTS seq_0_to_9;
CREATE TABLE seq_0_to_9 AS
   SELECT 0 AS seq UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4
    UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9;
DROP VIEW IF EXISTS seq_0_to_999;
CREATE VIEW seq_0_to_999 AS (
SELECT (a.seq + 10 * (b.seq + 10 * c.seq)) AS seq
  FROM seq_0_to_9 a
  JOIN seq_0_to_9 b
  JOIN seq_0_to_9 c
);
DROP VIEW IF EXISTS seq_0_to_999999;
CREATE VIEW seq_0_to_999999 AS (
SELECT (a.seq + (1000 * b.seq)) AS seq
  FROM seq_0_to_999 a
  JOIN seq_0_to_999 b
);

我在http://www.plumislandmedia.net/mysql/filling-missing-data-sequences-cardinal-integers/

上有更多关于此主题的内容