Let me first explain what I'm trying to do. I have a few tables that contain customer data. I'm trying to write a query that for certain customers will use last payment date (lstpaid), pay cycle (refi_max_daysdelin), and the current date to return a column that is a string that shows how many payments they have missed with the payment amount (payamt) after each date. It's easy enough to query all of the individual fields, but creating the string is where I am running into issues.
So for example let's say the current date is 05/07/14 (because it is), and let's say a customer's pay amount is 150.00. If their last payment date was 04/01/14 and their pay cycle is 14 days, they have missed 2 payments. So the string should return "04/15/14,150.00,04/29/14,150.00".
A coworker of mine got it working using CASE statements, but the problem with this method is that it is not dynamic. He had to write individual CASE statements into the MySQL to handle each new date / payamt added to the string. He went up to 15 CASES (x2 = 30 to get both date and payamt), the query was huge and bloated, and even then it's possible that we might need more. Basically it needs to be dynamic.
I just stripped it down to 2 cases the example SQL I'm posting here to make it easier to understand.
It seems like it should be simple enough to make this more dynamic, but I'm not sure how to proceed. In PHP I would just use a WHILE loop. Is that the best method in MySQL? I don't have any real experience with loops in MySQL. My understanding is that to use loops in MySQL requires creating stored procedures, is that correct? I would rather avoid that route if possible. But if that is the only way, a point in the right direction there would be appreciated.
Here is the SQL query with the CASE statements. As I said, it works, it's just not very feasible if you want it to handle large date ranges:
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
And here is an example of the output:
Customer Socsec Customer Name 02/28/2014 117.00 2014-04-11,117.00,2014-04-25,117.00