0

I have the following query (executed through PHP). How can I make it showing ZEROs if the result is NULL and is not shown.

select count(schicht) as front_lcfruh,
       kw,
       datum
from dienstplan
  left join codes on dienstplan.schicht = codes.lcfruh
  left join personal on personal.perso_id = dienstplan.perso_id
where codes.lcfruh != ''
and   personal.status = 'rezeption'
and   dienstplan.kw = '$kw'
group by dienstplan.datum
user2615859
  • 37
  • 1
  • 6
  • Use is_null or === operator. `is_null($result['column'])` `$result['column'] === NULL` – msd_2 Sep 24 '13 at 20:53
  • 4
    as much as I'm aware of(at least in Oracle) `count` can't return null. – gdoron Sep 24 '13 at 20:54
  • schicht comes from dienstplan, if the result is NULL means that there are no matching rows – user2615859 Sep 24 '13 at 20:56
  • @user2615859 Do you mean the query returns no rows at all? If so, "if the result is NULL" is highly misleading, as this implies you *do* get rows. –  Sep 24 '13 at 21:01
  • `where codes.lcfruh != '' and personal.status = 'rezeption'` :referring to codes.xxx and personal.yyy will effectively turn your `LEFT JOIN` into an ordinary `JOIN` – wildplasser Sep 25 '13 at 10:19

5 Answers5

0

I'm not entirely sure I understand the question, but I think you want this:

select count(codes.lcfruh) as front_lcfruh,
       dienstplan.kw,
       dienstplan.datum
from dienstplan
  left join codes on dienstplan.schicht = codes.lcfruh and codes.lcfruh <> ''
  left join personal on personal.perso_id = dienstplan.perso_id
and   personal.status = 'rezeption'
and   dienstplan.kw = $kw
group by dienstplan.datum, dienstplan.kw

If schicht comes from dienstplan there will always be a row for that (as that is the driving table). If I understand you correctly you want a 0 if no matching rows are found. Therefor you need to count the joined table.

Edit:
The condition where codes.lcfruh != '' turns the outer join back into an inner join because any "outer" row will have lcfruh as NULL and any comparison with NULL yields "unknown" and therefor the rows are removed from the final result. If you want to exclude rows in the codes table where the lcfruh has an empty string, you need to move that condition into the JOIN clause (see above).

And two more things: get used to prefixing your columns in a query with more than one table. That avoids ambiguity and makes the query more stable against changes. You should also understand the difference between number literals and string literals 1 is a number '1' is a string. It's a bad habit to use string literals where numbers are expected. MySQL is pretty forgiving as it always try to "somehow" work but if you ever user other DBMS you might get errors you don't understand.

Additionally your usage of group by is wrong and will lead to "random" values being returned. Please see these blog posts to understand why:

Every other DBMS will reject your query the way it is written now (and MySQL will as well in case you turn on a more ANSI compliant mode)

  • but I am still not getting ZEROs listed – user2615859 Sep 24 '13 at 21:42
  • @user2615859 Then you'll need to supply more details. Can you setup a small example on http://sqlfiddle.com? –  Sep 25 '13 at 06:20
  • sorry, i never used it. i though this could be simple. i need to list the data, in the code there is dienstplan.kw = '$kw', that is a week of the year, it has seven set of data (7 days). i need to get the count of schicht of every day nevertheless if COUNT is 0 or greater. hope this helps. – user2615859 Sep 25 '13 at 10:16
  • i found several examples but i do not know how to implement them. http://stackoverflow.com/questions/13965658/display-zero-by-using-count-if-no-result-returned-for-a-particular-case – user2615859 Sep 25 '13 at 10:25
  • i did it in sqlfiddle http://sqlfiddle.com/#!2/f03537/1, i am getting only the mathching rows, what i need is all the dates of the week listed, and show the count 0 if there are no matching rows on the date. – user2615859 Sep 25 '13 at 11:04
  • @user2615859: Thanks. Now I see it - although I should have seen that earlier. Your condition `where codes.lcfruh != ''` turns the outer join into an inner join. If you remove it, it should return what you want: http://sqlfiddle.com/#!2/9d0a3/1 Why did you add that condition? –  Sep 25 '13 at 11:12
  • @user2615859 Yes, see my comment to the OQ. (do you actually _read_ the comments, or do you just expect your work to be done by others?) – wildplasser Sep 25 '13 at 11:38
  • sorry wildplasser, I did not see that. – user2615859 Sep 25 '13 at 19:16
0

If you have no matching rows, then MySQL will return an empty set (here I have defined the fields at random, just to run the query):

mysql> CREATE TABLE dienstplan (kw varchar(10), datum integer, schicht integer, perso_id integer);
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE codes (lcfruh varchar(2));
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE personal (perso_id integer, status varchar(5));
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> select count(schicht) as front_lcfruh,
    ->        kw,
    ->        datum
    -> from dienstplan
    ->   left join codes on dienstplan.schicht = codes.lcfruh
    ->   left join personal on personal.perso_id = dienstplan.perso_id
    -> where codes.lcfruh != ''
    -> and   personal.status = 'rezeption'
    -> and   dienstplan.kw = '$kw'
    -> group by dienstplan.datum;

Empty set (0.00 sec)

You can check how many rows were returned by the query. In this case you will get zero.

So you could modify your code like this (pseudo code):

$exec = $db->execute($query);
if ($exec->error() !== false) {
    // Handle errors. Possibly quit or raise an exception.
}
if (0 == $exec->count())
{
    // No rows. We return a default tuple
    $tuple = array(
        'front_lcfruh' => 0,
        'kw'           => $kw,
        'datum'        => null
    );
    handleTuple($tuple);
} else {
    while($tuple = $exec->fetch()) {
        handleTuple($tuple);
    }
}

Where handleTuple() is the function that formats or otherwise manipulates the returned rows.

LSerni
  • 55,617
  • 10
  • 65
  • 107
0
SELECT dp.datum 
        , MIN(kw) -- To avoid adding it to GROUP BY clause
        , count(schicht) AS front_lcfruh
FROM dienstplan dp
LEFT JOIN codes co ON dp.schicht = co.lcfruh
LEFT JOIN personal pe ON pe.perso_id = dp.perso_id
WHERE dp.kw = '$kw' 
AND COALESCE(co.lcfruh, 'X') <> '' -- Handle NULLs, too
AND COALESCE(pe.status , 'rezeption' ) = 'rezeption' -- Handle NULLs, too
GROUP BY dp.datum
;
wildplasser
  • 43,142
  • 8
  • 66
  • 109
0

COUNT() can NEVER return NULL.

Lorenzo said (see comments) that I should provide references to help the SO community. Based on that feedback, I've edited my answer below.

  1. You should consult the documentation of the COUNT() function for MySQL here.
  2. You should also consider reading this article at Stack Overflow entitled "can COUNT(*) ever return NULL".
  3. Or this one entitled "When does COUNT(*) return NULL"
  4. Or this one entitled "COUNT(*) returns NULL"
  5. Or this one entitled "Return NULL if COUNT(*) is zero"
  6. Or this article on Oracle's forums entitled "COUNT never returns NULL?"
Community
  • 1
  • 1
amrith
  • 953
  • 6
  • 17
  • Please, improve the quality of your answer adding more context and references. – LorenzoDonati4Ukraine-OnStrike Sep 25 '13 at 12:27
  • Lorenzo; I am unclear what context you would like me to add. COUNT is a SQL function, and it always returns a number, never NULL. This is documented in most database documentation. I'm assuming that the person asking the question read at least that. It is also in most database 1xx level courses (yes, I've taught database courses). I'm happy to improve the quality of my answer but would love some direction what you are looking for. – amrith Sep 25 '13 at 16:27
  • Please, remember that the main focus here on SO is not on satisfying the OP's needs, but the needs of the community, which means having the best Q&A site. Your answer may be perfect for the OP, but it is too short by the SO standards. See this [meta SO](http://meta.stackexchange.com/questions/138738/should-i-give-short-answers-or-comments) thread. – LorenzoDonati4Ukraine-OnStrike Sep 25 '13 at 21:17
  • Sorry, that doesn't help. What do you want me to do in the answer? Give the questioner a link to the user documentation; fine, I'll do that. It won't make the answer any better for anyone but if you insist. – amrith Sep 26 '13 at 01:00
0
select COALESCE(count(schicht),0) as front_lcfruh,kw,datum
from dienstplan
  left join codes on dienstplan.schicht = codes.lcfruh
  left join personal on personal.perso_id = dienstplan.perso_id
where codes.lcfruh != ''
and   personal.status = 'rezeption'
and   dienstplan.kw = '$kw'
group by dienstplan.datum

just replace

count(schicht)

with

COALESCE(count(schicht),0)
MRRaja
  • 1,073
  • 12
  • 25