List every month in an intevalo, or in the query or in the programming?

Asked

Viewed 800 times

3

I’m making a chart that lists a certain amount per month, but can have mès that has nothing, with this returns me no value and does not list in the chart.

I don’t know if I should make the change in the query or programming, can anyone help me?

My query looks like this:

SELECT DATE_FORMAT(dt_validade, '%y-%m') as anoMes, count(*) as qtde
FROM tabela
WHERE dt_validade > '{$today}'
GROUP BY anoMes
ORDER BY anoMes

her return is more or less that

anoMes  | qtde
14-08   | 2
14-09   | 5
14-12   | 10
14-12   | 10
14-12   | 10
15-01   | 1
15-03   | 1

and with that, in php I run a loop in the result, I play the dice for an array that sends a json_encode for the data to the graph, but with this will only show me in the graph data of the months 08, 09 and 12, but I need to show also of the months 10 and 11 with zero values.

And in short, what I did in programming was this:

$cols = array(
    array(
        'Período', 
        'Quantidade'
    )
);
$rows = array();

$query = "A query passada";    
$result = $query->result();
foreach ($result as $r) {
    array_push($rows, array(
        $r->mesAno, 
        (int) $r->qtde
    ));
}    

$dados = array_merge($cols, $rows);     

return json_encode($dados);

And as a suggestion given to me, the expected result is this:

anoMes  | qtde
14-08   | 2
14-09   | 5
14-10   | 0
14-11   | 0
14-12   | 10
15-01   | 1
15-03   | 1

Follow link with build on SQLFIDDLE, so I guess I can get a little clearer

  • I really can’t understand your question. How else could you send a query to BD but through SQL? If the question is something like CURRENT_DATE vs date("2014-01-01"), it matters little! Your query will be sent only once.

  • I also see no other way to send my query to BD if not with sql, so much so that’s what I’m doing and I intend to do. But the point is that I need the result with every month even with the amount reset and I don’t know how to do it and I don’t even know if I do it in my query or in the programming.

  • In this case, specifically, no matter the method. Choose the most practical.

  • And you can help me in what is the most practical, and how to do, being that I am thinking and trying and not getting a solution!? Thank you

  • 1

    @Marcelodiniz - Since our colleagues had some doubts in understanding your problem, my suggestion is that you edit the post and add a 'expected result'.. example: 08-14 |2 ... 09-14 | 5 ... 10-14 | 0 ... 11-14| 0.. 12-14 | 10 I think it would be clearer.

3 answers

2

It wasn’t the most beautiful thing in the world, but it worked:

$rows = array();

$query = "SELECT DATE_FORMAT(dt_validade, '%m-%y') as anoMes, count(*) as qtde
          FROM tabela
          WHERE dt_validade > now()
          GROUP BY anoMes
          ORDER BY dt_validade";    

$result = $query->result();
foreach ($result as $r) {
    $rows[$r->mesAno] = (int) $r->qtde;
}    

reset($rows);
list($mes, $ano) = explode('-', key($rows));
$current = strtotime(($ano+2000).'-'.$mes.'-01');

end($rows);
list($mes, $ano) = explode('-', key($rows));
$last = strtotime(($ano+2000).'-'.$mes.'-01');

$dates = array();
while( $current <= $last ) { 
    $dates[date('m-y', $current)] = 0;
    $current = strtotime('+1 month', $current);
}

$rows = array_merge($dates, $rows);
$dados = array( array('Período', 'Quantidade'));
foreach($rows as $key => $value) $dados[] = array($key, $value);

return json_encode($dados);
  • Look at it, really, as you said, it really worked, it is not the most beautiful thing, but it is not always, and even by not yet I will mark as accepted answer, but already as useful ;) .. I really appreciate it, now I’m going to see better what to do here with this part, but it sure has given me a light. Valew

  • So @Jader as I said, the solution you went through worked, but then I went to do a test putting data for January and March 2015 so it broke me all over. So one of the things I’ve seen that I’d have to change is in the query, something I’ve already done, now I’m seeing to change in the programming too, in case I know something thank you.

  • I tested with intervals from 12-14 to 05-15 and worked well, note that I changed the way the $Rows variable is populated, the same enters as key, take all my code and put only the query.

  • Yes, I noticed what you said and it still didn’t work, so I changed the query how it can be seen (even in sqlfiddle) and tbm made a small change to the code you posted that really helped. The changes I made were change month by year that with this it returns the correct sequence.

  • Really the correct order is fundamental, and only with the year ahead Mysql will order correctly, in my tests I populated the array manually in the correct order...

  • 1

    @Marcelodiniz I just realized that I didn’t need to change the date format, just change the order by to: ORDER BY dt_validade tested on sqlfiddle and works perfectly.

  • Boy, what a head I was, I didn’t even realize it either, and I had a little too much work here. Valew and that is to serve of lesson not to forget of these small details.

Show 2 more comments

1

My knowledge in PHP is very limited, but I can try to help with a bank-side solution.

Set the period

SELECT @mindate = MIN(dt_validade), @maxdate = MAX(dt_validade) FROM tabela

Partial result:

|                    @mindate |                     @maxdate |
|-----------------------------|------------------------------|
| July, 30 2014 00:00:00+0000 | March, 15 2015 00:00:00+0000 |

Get the list of months between the two periods: Store in temporary table

CREATE TEMPORARY TABLE 
IF NOT EXISTS 
ListaAnoMes AS
SELECT Date_format(m1, '%y-%m') AS anoMes 
FROM   (SELECT ( @mindate - INTERVAL Dayofmonth(@mindate)-1 day ) + 
               INTERVAL m month AS 
                      m1 
        FROM   (SELECT @rownum := @rownum + 1 AS m 
                FROM   (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t1, 
                       (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t2, 
                       (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t3, 
                       (SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4) t4, 
                       (SELECT @rownum :=- 1) t0) d1) d2 
WHERE  m1 <= @maxdate 
ORDER  BY m1; 

Partial result:

SELECT * FROM LISTAANOMES

| ANOMES |
|--------|
|  07-14 |
|  08-14 |
|  09-14 |
|  10-14 |
|  11-14 |
|  12-14 |
|  01-15 |
|  02-15 |
|  03-15 |

Cross the two tables

SELECT         B.AnoMes,
               Count(a.id) as qtde
FROM           ListaAnoMes as B
LEFT JOIN      tabela as A 
           ON  DATE_FORMAT(A.dt_validade, '%m-%y') = B.anoMes
GROUP BY       B.AnoMes

Upshot:

| ANOMES | QTDE |
|--------|------|
|  01-15 |    1 |
|  02-15 |    0 |
|  03-15 |    1 |
|  07-14 |    1 |
|  08-14 |    2 |
|  09-14 |    5 |
|  10-14 |    0 |
|  11-14 |    0 |
|  12-14 |   10 |
  • I have not yet tested your solution to my problem as well, but I will take the test. But so, from what I saw, I understand more about programming than the bank side has become easier to solve with the solution that @Jader went through for future maintenance, but I understood what happened and found interesting too.

0

You want a date interval ?

SELECT DATE_FORMAT(dt_validade, '%m-%y') as mesAno, count(*) as qtde
FROM tabela
WHERE dt_validade > '{$today}' OR dt_validade = NULL OR dt_validade = ''
GROUP BY mesAno

I don’t know if the default is null or empty string, depending on you don’t need 2 or, only one

  • I don’t really have an exact end date. What I want is for you to list me every month from the first to the last found from today’s date.

  • Now I understand what you want. I’ll edit

  • Honestly, I do not know if you understood, because from what I saw of your amendment what changed was in WHERE that now is not searching in an interval (between) but seeking date from today and date null or blank. But that does not solve the problem that I have to list the months in the interval that the consultation brings me. The consultation returns to me the months 8, 9 and 12 that are the months that have record, but I need to return the months 8, 9, 10, 11 and 12, and the months 10 and 11 will return with the amount equal to zero.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.