2016-11-12 81 views
0

我有下面的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()但没有成功的东西。

+0

但为什么这一切的并发症。为什么不用juse看看ledger_date? – e4c5

+1

为什么不直接使用'AND ledger_date BETWEEN 2016-07-13 AND whatever' ???或'WHERE ledger_date ='2016-08-15'' – AbraCadaver

+0

因为我需要循环每一个日期出于其他原因,并且分类账表每天都没有记录。顺便说一下,我已经编辑了这个问题来更清楚地解释这个问题 – ratherBeKiting

回答

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的方便,花花公子表seq_0_to_999999是为您预定义的sequence table。否则,你可以很容易地将其创建为一系列观点,如:

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/