简体   繁体   中英

How to get a record for each group in SQL even when there are no records in the table?

I'm querying a table in SQL, grouping records by their Datepart("ww",date) and then year but I want to group them biweekly actually but I couldn't find any resources on how I could do that easily. So instead I'm just grouping them by week number and year and then looping through and adding consecutive week totals together.

The issue is that the query does not return a row when there are no records for that week so I can't simply add the next 2 rows together. I'm wondering how I would return a row for each week even if there are not records for that week in the database.

Here is the query:

SELECT 
    SUM(T.task_minutes) AS TASK_TIME,
    (SELECT SUM(hours_limit)
     FROM project_hour_monitors
     WHERE project_id = MAX(P.project_id)) AS TOTAL_HOURS_CAP,
    DATEPART(week, T.task_date),
    DATEPART(year, T.TASK_DATE)
FROM   
    PROJECTS AS P
LEFT JOIN 
    tasks AS T ON T.project_id = P.project_id
WHERE  
    P.project_id = 18155
    AND T.task_date >= P.date_posted
    AND T.task_date <= P.due_date
    AND T.monitor_id IS NOT NULL
    AND T.monitor_id <> 0
GROUP BY 
    DATEPART(week, T.task_date), DATEPART(year, T.TASK_DATE)
ORDER BY 
    DATEPART(year, T.TASK_DATE), DATEPART(week, T.task_date)

Any help is appreciated.

How about / 2 ? Presumably you want something just a little bit more complicated:

SELECT YEAR(T.Task_Date),
       MIN(DATEPART(WEEK, T.Task_Date)),
       Sum(T.task_minutes) AS TASK_TIME
FROM PROJECTS P JOIN
     tasks T
     ON T.project_id = P.project_id
WHERE  P.project_id = 18155 AND
       T.task_date >= P.date_posted AND
       T.task_date <= P.due_date AND
       T.monitor_id IS NOT NULL
       T.monitor_id <> 0
GROUP BY CEILING(Datepart(week, T.task_date) / 2.0), YEAR(T.TASK_DATE)
ORDER BY MAX(T.TASK_DATE);

The CEILING(x / 2.0) makes the groups 1/2, 3/4, 5/6, and so on. That is presumably what you want.

I made some other changes to the query:

  • INNER JOIN instead of LEFT JOIN . The WHERE turns the logic into an INNER JOIN anyway, so now the query is more internally consistent.
  • YEAR() instead of DATEPART() . It is just simpler.
  • I changed the ORDER BY . This also orders by date, but it is simpler.

EDIT:

If you actually want the left join version:

SELECT YEAR(T.Task_Date),
       MIN(DATEPART(WEEK, T.Task_Date)),
       Sum(T.task_minutes) AS TASK_TIME
FROM PROJECTS P JOIN
     tasks T
     ON T.project_id = P.project_id AND
        T.task_date >= P.date_posted AND
        T.task_date <= P.due_date AND
        T.monitor_id IS NOT NULL
        T.monitor_id <> 0
WHERE  P.project_id = 18155 AND
GROUP BY CEILING(Datepart(week, T.task_date) / 2.0), YEAR(T.TASK_DATE)
ORDER BY MAX(T.TASK_DATE);

To answer your week datepart issue first, you can try simple division of integers on SQL and it will give you the integer result. For example, if you want to group by every other week, you could do datepart(week, t.task_date) / 2 .

To answer your null result question, you can address this in various ways, but I would first try putting an isnull statement in your SUMs. That might be enough for what you want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM