如何在MySQL中返回包含1到N值的动态创建的字符串?

时间:2014-05-07 20:54:05

标签: php mysql loops dynamic

首先让我解释一下我要做的事情。我有几个包含客户数据的表。我试图写一个查询,某些客户将使用上次付款日期(lstpaid),付费周期(refi_max_daysdelin)和当前日期返回一个字符串,该字符串显示他们错过了多少付款每个日期之后的付款金额(payamt)。查询所有单个字段非常容易,但创建字符串是我遇到问题的地方。

例如,让我们说当前日期是05/07/14(因为它是),并且让我们说顾客的工资额是150.00。如果他们的最后付款日期是2014年1月4日,他们的付款周期为14天,则他们错过了2笔付款。所以字符串应该返回" 04/15 / 14,150.00,04 / 29 / 14,150.00"。

我的同事使用CASE语句让它工作,但这种方法的问题在于它不是动态的。他必须在MySQL中编写单独的CASE语句来处理添加到字符串中的每个新日期/ payamt。他上升到15个案例(x2 = 30来获得日期和付款),查询量巨大且臃肿,即便如此,我们可能还需要更多。基本上它需要是动态的。

我刚刚将其删除为2个案例,我在这里发布了示例SQL,以便于理解。

似乎应该足够简单,使其更具动态性,但我不确定如何继续。在PHP中,我只使用WHILE循环。这是MySQL中最好的方法吗?我对MySQL的循环没有任何实际经验。我的理解是在MySQL中使用循环需要创建存储过程,这是正确的吗?如果可能的话,我宁愿避开那条路线。但如果这是唯一的方法,那么正确的方向就会受到赞赏。

这是带有CASE语句的SQL查询。正如我所说,它有效,如果你想要它处理大日期范围,它就不太可行了:

SELECT DISTINCT xyzcustunq.socsec, xyzacct.name, xyzacct.opendt AS agreementdate, xyzacct.payamt, 
CONCAT_WS(',',duedate1,paymentamt1,duedate2,paymentamt2) AS duedates

FROM xyzcustunq 
INNER JOIN xyzacct ON (xyzcustunq.socsec=xyzacct.socsec) 
INNER JOIN xyzclass ON (xyzacct.class=xyzclass.class)

LEFT OUTER JOIN 
(
    SELECT xyzacct.socsec AS zsocsec,

    CASE when (xyzacct.lstpaid NOT IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.lstpaid, INTERVAL +(xyzclass.refi_max_daysdelin) DAY) <= CURDATE()))
    then (DATE_ADD(xyzacct.lstpaid, INTERVAL +(xyzclass.refi_max_daysdelin) DAY))
    when (xyzacct.lstpaid IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.opendt, INTERVAL +(xyzclass.refi_max_daysdelin) DAY) <= CURDATE())) 
    then (DATE_ADD(xyzacct.opendt, INTERVAL +(xyzclass.refi_max_daysdelin) DAY))
    else NULL end 
    AS duedate1,

    CASE when (xyzacct.lstpaid NOT IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.lstpaid, INTERVAL +(xyzclass.refi_max_daysdelin) DAY) <= CURDATE()))
    then xyzacct.payamt
    when (xyzacct.lstpaid IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.opendt, INTERVAL +(xyzclass.refi_max_daysdelin) DAY) <= CURDATE())) 
    then xyzacct.payamt
    else NULL end 
    AS paymentamt1,

    CASE when (xyzacct.lstpaid NOT IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.lstpaid, INTERVAL +(xyzclass.refi_max_daysdelin*2) DAY) <= CURDATE())) 
    then (DATE_ADD(xyzacct.lstpaid, INTERVAL +(xyzclass.refi_max_daysdelin*2) DAY))
    when (xyzacct.lstpaid IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.opendt, INTERVAL +(xyzclass.refi_max_daysdelin*2) DAY) <= CURDATE())) 
    then (DATE_ADD(xyzacct.opendt, INTERVAL +(xyzclass.refi_max_daysdelin*2) DAY))
    else NULL end 
    AS duedate2,

    CASE when (xyzacct.lstpaid NOT IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.lstpaid, INTERVAL +(xyzclass.refi_max_daysdelin*2) DAY) <= CURDATE()))
    then xyzacct.payamt
    when (xyzacct.lstpaid IN ('00-00-0000', '00/00/0000') AND 
    (DATE_ADD(xyzacct.opendt, INTERVAL +(xyzclass.refi_max_daysdelin*2) DAY) <= CURDATE())) 
    then xyzacct.payamt
    else NULL end 
    AS paymentamt2

    FROM xyzcustunq 
   INNER JOIN xyzacct ON (xyzcustunq.socsec=xyzacct.socsec) 
   INNER JOIN xyzclass ON (xyzacct.class=xyzclass.class)
    WHERE 
    (xyzacct.pstatus = 'A')

    GROUP BY xyzacct.socsec
) z ON (xyzacct.socsec = z.zsocsec)  

WHERE 
(xyzacct.pstatus = 'A') AND
(xyzacct.curbal > 0.00) AND
(xyzacct.socsec LIKE '%490%')

ORDER BY xyzacct.name

以下是输出的示例:

Customer Socsec Customer Name 02/28/2014 117.00 2014-04-11,117.00,2014-04-25,117.00

1 个答案:

答案 0 :(得分:0)

我会在MySQL中创建查询并以PHP格式处理结果。

PHP循环更快,MySQL查询大量数据的速度更快。

MySQL的结果应该是一个变量中所有可能的支付日期的列表以及客户在该日期完成的支付金额。这需要左外连接。 然后在PHP中处理每一行并创建字符串。

查询基本上是这样的:

select abc.paydate, cust.paydate, cust.amount from paydates abc left join customerpayings     
cust on abc.paydate=cust.paydate;

通过此查询,您还可以在上次完成付款之前找到丢失的付款。

如果您需要在MySQL中创建循环,我肯定会编写一个存储过程并使用游标。它们是为此目的而制作的。存储过程的一个很大的优点是它们是预编译的,因此可以很好地防御SQL注入攻击。