Hi. A little explanation of the table usage would have been nice. E.g. it's not clear to me, if shift 232 is also listed in the "shifts" table or not. I presume the latter from now (in which case "shifts" is more like a "did_show_shifts").
Also, you did not specify what special cases are to be taken care of. E.g. can there be volunteers which do not have a shift assigned yet? Can there be a shift in the future? And so on... I presume that the tables reflect complete recordings _after_ each shift. On Fri, Feb 15, 2002 at 11:38:29PM -0800, [EMAIL PROTECTED] wrote: > I'm stumped -- which isn't saying much because I'm hardly a scientist. > I am struggling to write a query that will tell me how many times a new > volunteer ( defined as a volunteer who has never worked a shift ) did > not show up for his shift (first shift). From my data I would > eventually like to be able to say: a brand new volunteer does not show > up for his shift 1 in x times. Well, either one of my presumptions is false or a different layout would probably better, namely: shifts SID | WHEN | VID | SHOW ------------------------------- 230 | 2000-01-28 | 584 | yes 231 | 2000-02-01 | 485 | yes 232 | 2000-02-01 | 259 | no 233 | 2000-02-03 | 147 | yes ... (avoiding DATE because it's a reserved word) In this case your question would be a variation of the one described in the tutorial section of the manual (getting the rows for the group-wise smallest (=date) value of a column): http://www.mysql.com/doc/e/x/example-Maximum-column-group-row.html Your question is like "for each volunteer, find whether he showed up (=SHOW) for his first shift (minimum WHEN)". See the metioned manual section for more detail. So this would be something like CREATE TEMPORARY TABLE tmp SELECT VID, MIN(WHEN) AS WHEN FROM shifts GROUP BY VID; SELECT t.VID, t.DATE, s.SHOW FROM tmp t, shifts s WHERE s.VID=t.VID AND s.WHEN=t.WHEN; This gives you, for each volunteer, when his first shift was and if he showed up. You want to know, the percentage of how often a volunteer misses his first shift in avarage. You get this, if you replace the SELECT clause by: SELECT AVG( IF( s.SHOW = 'no', 1, 0 ) ) FROM ... In MySQL a comparision returns 1, 0 or NULL and therefore this can be abbriviated as SELECT AVG( s.SHOW = 'no' ) FROM ... The disadvantage of using AVG() to evaluate the number of posivite hits is that the query has to go through the whole tmp table and cannot use indexes. So, if your tables are not small (>10000 rows) or you do this query not only once, you want to use the following instead: (of course, this presume that you created an index on tmp.SHOW!) SELECT @volunteers := COUNT(VID) FROM volunteer; SELECT COUNT(*) / @volunteers FROM tmp t, shifts s WHERE s.VID=t.VID AND s.WHEN=t.WHEN AND s.SHOW='no'; This presumes, that there are no VID in volunteer, that are not in shifts and vice versa. If that's not true, use instead SELECT @volunteers := COUNT(DISTINCT v.VID) FROM volunteer v, shifts s WHERE v.VID = s.VID Okay, so your final queries could look like (the simple way) SELECT @volunteers := COUNT(VID) FROM volunteer; CREATE TEMPORARY TABLE tmp SELECT VID, MIN(WHEN) AS WHEN FROM shifts GROUP BY VID; SELECT AVG( s.SHOW = 'no' ) FROM tmp t, shifts s WHERE s.VID=t.VID AND s.WHEN=t.WHEN; Now back to your original table layout. Without going in-depth again, I guess the following should work (presuming that SID in shifts and no_show_shifts are distinct): SELECT @volunteers := COUNT(VID) FROM volunteer; CREATE TEMPORARY TABLE tmp SELECT VID, MIN(WHEN) AS WHEN, 'yes' AS SHOW FROM shifts GROUP BY VID; INSERT INTO tmp SELECT VID, MIN(WHEN), 'no' AS SHOW FROM no_show_shifts GROUP BY VID; CREATE TEMPORARY TABLE tmp2 SELECT VID, MIN(WHEN) AS WHEN FROM tmp GROUP BY VID; SELECT AVG( s.SHOW = 'no' ) FROM tmp2 t, tmp s WHERE s.VID=t.VID AND s.WHEN=t.WHEN; Or with a more complex SELECT (don't know if it's faster or slower without testing): SELECT @volunteers := COUNT(VID) FROM volunteer; CREATE TEMPORARY TABLE tmp SELECT v.VID, MIN(s.WHEN) AS WHEN_YES, MIN(n.WHEN) AS WHEN_NO FROM shifts LEFT JOIN shifts s ON s.VID=v.VID LEFT JOIN no_show_shifts n ON n.VID=v.VID GROUP BY VID; SELECT AVG( IS_NULL(WHEN_YES) OR ( !ISNULL(WHEN_NO) AND WHEN_NO<WHEN_YES ) ) FROM tmp t, shifts s WHERE s.VID=t.VID AND s.WHEN=t.WHEN; Btw, this presume that not both, MIN(shifts.WHEN) and MIN(no_show_shifts.WHEN) can be NULL for a certain VID at the same time, i.e. that for each VID there is a row either in shifts or in no_show_shifts. Of course, in MySQL 4.x, you could use UNION to simplify that query. But using UNION is a sign for strange table design (justified by needs or not) and this is why I started my first example with a changed table layout. And, as initally said, maybe I made the false assumptions for the gaps. And depending on your needs, you may want to lock the tables for the queries as shown in the mentioned manual page. So, and now... was I blind and someone shows me that there is a far easier way? ;-) Bye, Benjamin. PS: Ah well, and note, that I did test none of the queries, so beware of typos and so on. On Fri, Feb 15, 2002 at 11:38:29PM -0800, [EMAIL PROTECTED] wrote: > I have three tables: > > volunteer > VID | Name > ----------------- > 524 | Joe Doe > 254 | Karen Smith > 485 | Bob Nesbit > > shifts > SID | DATE | VID > --------------------------- > 230 | 2000-01-28 | 584 > 231 | 2000-02-01 | 485 > 233 | 2000-02-03 |147 > 234 | 2000-02-04 | 584 > > no_show_shifts > SID | DATE | VID > --------------------------- > 232 | 2000-02-01 | 259 > 239 | 2000-02-08 | 369 > > > Is it possible to write a query that will solve this problem? If so, > can anyone tell me how I can do it? > If not what other data do I need? Any help is appreciated. > > Richard > --------------------------------------------------------------------- Before posting, please check: http://www.mysql.com/manual.php (the manual) http://lists.mysql.com/ (the list archive) To request this thread, e-mail <[EMAIL PROTECTED]> To unsubscribe, e-mail <[EMAIL PROTECTED]> Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php