0

I am writing a report on data based on new customers for each given month, starting from the earliest month an order was present all the way to the last month that any orders are present (I realize the current code will stop on any month that doesn't have new customers, and will fix later...)

Some background-- I'm using the Flourish Framework (www.flourishlib.com).. The first month/year is set correctly because I have error log'd it out. The first month with orders is 4/2013.

The problem is that for some reason, MySQL randomly returns an empty result at some point that is completely random. I have run the query for that month/year that it returns an empty result for in a MySQL client and it is not an empty result. The script itself proves this to be the case as where it returns the empty result is random and it will go further than it did before sometimes showing the correct information.

I have tried sleeping in between queries, as I originally thought maybe it was throttling or something, no go. Still the same exact behavior. I have tried using retries (when it encounters a count of 0 it will retry up to X times) and EVERY TIME it's empty, which means it cannot be one of those "sometimes it craps out, try again" type of scenarios.

Here is the code as it is now:

function newClients($month, $year) {
    $db = fORMDatabase::retrieve();

    $noobs = $db->query("
        SELECT
        id,
        email,
        (
            SELECT completed
            FROM orders
            WHERE client_id = clients.id
            ORDER BY completed ASC
            LIMIT 1
        ) as first_order
        FROM clients
        HAVING first_order IS NOT NULL
        AND MONTH(first_order) = '$month'
        AND YEAR(first_order) = '$year'
        AND email NOT LIKE '*@********.com'
        AND email NOT LIKE '%@********.com'
        AND email NOT LIKE '%@********.com'
        AND email NOT LIKE '%@********.com'
        AND email NOT LIKE '%@********.com'
        AND email NOT LIKE '%@********.org'
        AND email != '********@gmail.com'
        AND email != '********@********.net'
    ")->fetchAllRows();
    return $noobs;
}

$currentMonth = $theFirst['month'];
$currentYear = $theFirst['year'];

$retries = 0;
$noobs = newClients($currentMonth, $currentYear);
while (count($noobs) > 0 || $retries < 3) {
    if (count($noobs) == 0) {
        error_log('retry #' . ($retries + 1) . '...');
        $retries++;
        $noobs = newClients($currentMonth, $currentYear);
        error_log('count: ' . count($noobs));
        sleep(5);
        continue;
    }
    error_log("loop $currentMonth / $currentYear: " . count($noobs));
    if ($currentMonth >= 12) {
        $currentYear++;
        $currentMonth = 1;
    } else {
        $currentMonth++;
    }
    sleep(1);
    $noobs = newClients($currentMonth, $currentYear);
    error_log('count: ' . count($noobs));
}

Couple additional things.. I censored the email addresses for obvious reasons, and I did look at the actual returned data in the MySQL client, it is correct, and I also did vardump the actual array returned and it is indeed empty. (in case you're wondering that maybe count is counting incorrectly or who knows.. I thought maybe it was a countable object/non-array issue or quirk or something)

There may be some confusion as to the retries etc. as that has nothing to do with my desired outcome and were only attempts to solve the issue, here is the original code:

$noobs = newClients($currentMonth, $currentYear);
while (count($noobs) > 0) {
    error_log("loop $currentMonth / $currentYear: " . count($noobs));
    if ($currentMonth >= 12) {
        $currentYear++;
        $currentMonth = 1;
    } else {
        $currentMonth++;
    }
    $noobs = newClients($currentMonth, $currentYear);
    error_log('count: ' . count($noobs));
}
Alex
  • 121
  • 11
  • `$currentMonth >= 12`? That'd mean you're skipping December and only allowing Jan->Nov. It should be either `> 12` or `>= 13`. This isn't Javascript. Months in PHP and MySQL are 1->12, not 0->11 – Marc B Jan 07 '15 at 21:31
  • Hm. I am not sure if this is an issue? Examining the code now but since you came up with this, by the point that this code is ran, it would already have gotten december, as in the end of the previous loop it goes from 11 to 12.. Am I incorrect in this? – Alex Jan 07 '15 at 21:50
  • december, not november.. (i corrected it but just for notification purposes) – Alex Jan 07 '15 at 21:51

1 Answers1

0

sorry this is probably not really an answer but too big for comments.

  1. i'm not confident this error is in PHP or flakiness with the db connection can you modify your retry to print out the query and run it in your mysql client by hand ?

maybe you have weird inputs ?

  1. try adding a null check to this

        SELECT completed
        FROM orders
        WHERE client_id = clients.id
        AND completed IS NOT NULL
        ORDER BY completed ASC
        LIMIT 1
    

i suspect you have your db set to NULLs first and they float to the top of your ordering

David Chan
  • 7,347
  • 1
  • 28
  • 49
  • Yes, they do, that's why I have the first part of the having clause is "first_order IS NOT NULL" – Alex Jan 07 '15 at 21:49
  • the having clause does not guarantee there are no valid "completed" because it's only checking the first one thanks to the ORDER BY / LIMIT. eg: (NULL, 1 ,2, 3) LIMIT 1, having only checks the NULL – David Chan Jan 07 '15 at 21:54
  • `AND completed IS NOT NULL` would be the correct way to do this right? I added that after the WHERE line and it is still having the same issue. I am wondering if maybe because I am limiting it to one, if that is the problem? – Alex Jan 07 '15 at 21:59
  • I printed out the queries and ran the last one that returned no results by hand (copy/paste) and it returned a bunch of stuff. I am wondering if something weird is going on, as I put to print the query if the count is 0, and it didn't print anything. I had to just print all of them before running the query. Could PHP be dying? – Alex Jan 07 '15 at 22:13