How to group and count by date and 8-hr interval on those dates in datetime SQL column?












1















I have a table with a column visit_date that is a datetime object with format YYYY-MM-DD HH:MI:SS that looks like the following:



visit_date         |visit_id
-------------------|-----
2010-11-01 00:02:00|92314
2010-11-01 23:05:21|23498
2010-11-01 12:42:31|12343
2010-11-02 05:13:21|79881
2010-11-02 14:35:15|22134
2010-11-02 16:12:23|12348
2010-11-03 01:22:44|12384
2010-11-03 05:23:41|12394
2010-11-03 15:13:55|99384


I would like to group by date and by 8-hr window on that date such that I have:



interval           |count
-------------------|-----
2010-11-01 00:00:00|1
2010-11-01 08:00:00|2
2010-11-01 16:00:00|3
2010-11-02 00:00:00|4
2010-11-02 08:00:00|5
2010-11-02 16:00:00|6
2010-11-03 00:00:00|7
2010-11-03 08:00:00|8
2010-11-03 16:00:00|9


My original query (using only dates) was:



SELECT CAST(visit_date as DATE), count(1) as count
FROM table
GROUP BY CAST(visit_date as DATE)
ORDER BY CAST(visit_date as DATE)


But that only groups by date.



Is there a recommended way to get interval counts for each interval per day? I have seen implementations using DATEADD and DATEPART but not sure which makes the most sense in this situation.



Thanks!










share|improve this question


















  • 1





    How can you make count column? I don't see any logic in it

    – D-Shih
    Nov 19 '18 at 23:19
















1















I have a table with a column visit_date that is a datetime object with format YYYY-MM-DD HH:MI:SS that looks like the following:



visit_date         |visit_id
-------------------|-----
2010-11-01 00:02:00|92314
2010-11-01 23:05:21|23498
2010-11-01 12:42:31|12343
2010-11-02 05:13:21|79881
2010-11-02 14:35:15|22134
2010-11-02 16:12:23|12348
2010-11-03 01:22:44|12384
2010-11-03 05:23:41|12394
2010-11-03 15:13:55|99384


I would like to group by date and by 8-hr window on that date such that I have:



interval           |count
-------------------|-----
2010-11-01 00:00:00|1
2010-11-01 08:00:00|2
2010-11-01 16:00:00|3
2010-11-02 00:00:00|4
2010-11-02 08:00:00|5
2010-11-02 16:00:00|6
2010-11-03 00:00:00|7
2010-11-03 08:00:00|8
2010-11-03 16:00:00|9


My original query (using only dates) was:



SELECT CAST(visit_date as DATE), count(1) as count
FROM table
GROUP BY CAST(visit_date as DATE)
ORDER BY CAST(visit_date as DATE)


But that only groups by date.



Is there a recommended way to get interval counts for each interval per day? I have seen implementations using DATEADD and DATEPART but not sure which makes the most sense in this situation.



Thanks!










share|improve this question


















  • 1





    How can you make count column? I don't see any logic in it

    – D-Shih
    Nov 19 '18 at 23:19














1












1








1








I have a table with a column visit_date that is a datetime object with format YYYY-MM-DD HH:MI:SS that looks like the following:



visit_date         |visit_id
-------------------|-----
2010-11-01 00:02:00|92314
2010-11-01 23:05:21|23498
2010-11-01 12:42:31|12343
2010-11-02 05:13:21|79881
2010-11-02 14:35:15|22134
2010-11-02 16:12:23|12348
2010-11-03 01:22:44|12384
2010-11-03 05:23:41|12394
2010-11-03 15:13:55|99384


I would like to group by date and by 8-hr window on that date such that I have:



interval           |count
-------------------|-----
2010-11-01 00:00:00|1
2010-11-01 08:00:00|2
2010-11-01 16:00:00|3
2010-11-02 00:00:00|4
2010-11-02 08:00:00|5
2010-11-02 16:00:00|6
2010-11-03 00:00:00|7
2010-11-03 08:00:00|8
2010-11-03 16:00:00|9


My original query (using only dates) was:



SELECT CAST(visit_date as DATE), count(1) as count
FROM table
GROUP BY CAST(visit_date as DATE)
ORDER BY CAST(visit_date as DATE)


But that only groups by date.



Is there a recommended way to get interval counts for each interval per day? I have seen implementations using DATEADD and DATEPART but not sure which makes the most sense in this situation.



Thanks!










share|improve this question














I have a table with a column visit_date that is a datetime object with format YYYY-MM-DD HH:MI:SS that looks like the following:



visit_date         |visit_id
-------------------|-----
2010-11-01 00:02:00|92314
2010-11-01 23:05:21|23498
2010-11-01 12:42:31|12343
2010-11-02 05:13:21|79881
2010-11-02 14:35:15|22134
2010-11-02 16:12:23|12348
2010-11-03 01:22:44|12384
2010-11-03 05:23:41|12394
2010-11-03 15:13:55|99384


I would like to group by date and by 8-hr window on that date such that I have:



interval           |count
-------------------|-----
2010-11-01 00:00:00|1
2010-11-01 08:00:00|2
2010-11-01 16:00:00|3
2010-11-02 00:00:00|4
2010-11-02 08:00:00|5
2010-11-02 16:00:00|6
2010-11-03 00:00:00|7
2010-11-03 08:00:00|8
2010-11-03 16:00:00|9


My original query (using only dates) was:



SELECT CAST(visit_date as DATE), count(1) as count
FROM table
GROUP BY CAST(visit_date as DATE)
ORDER BY CAST(visit_date as DATE)


But that only groups by date.



Is there a recommended way to get interval counts for each interval per day? I have seen implementations using DATEADD and DATEPART but not sure which makes the most sense in this situation.



Thanks!







sql sql-server






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 19 '18 at 22:19









user50710user50710

106112




106112








  • 1





    How can you make count column? I don't see any logic in it

    – D-Shih
    Nov 19 '18 at 23:19














  • 1





    How can you make count column? I don't see any logic in it

    – D-Shih
    Nov 19 '18 at 23:19








1




1





How can you make count column? I don't see any logic in it

– D-Shih
Nov 19 '18 at 23:19





How can you make count column? I don't see any logic in it

– D-Shih
Nov 19 '18 at 23:19












3 Answers
3






active

oldest

votes


















2














Add the hours in to what you group and count:



SELECT 
CAST(visit_date as DATE),
HOUR(visit_date)/8 as ival8h
count(1) as count
FROM table
GROUP BY CAST(visit_date as DATE), HOUR(visit_date)/8
ORDER BY CAST(visit_date as DATE)


The hour function returns the hour number of the passed date, divide it by 8 to get an int of the interval, so 0 to 7 becomes 0, 8 to 16 becomes 1 etc



If you want it back as a time pegged to a round 8h multiply it by 8 again and format it to NN:00:00, or add it to the date, thus:



SELECT 
DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME) as quantized_date,
count(1) as count
FROM table
GROUP BY DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME)
ORDER BY CAST(visit_date as DATE)


This basically rounds the hours down to the lesser 8h market and adds that to midnight. Two casts are required (probably) on the date because DATEADD won't add hours to a date, only a datetime but we need the cast to date to peg the tine element to midnight



If you want there to be a date and a 0 count for periods where no events took place, use a numbers table or row generator and create a sequence of dates to left join your real data onto, then count the real data grouped by the fake dates






share|improve this answer


























  • Thanks, this makes a lot of sense. To reformat it, would I simply substitute HOUR(visit_date)/8 as ival8h with FORMAT(HOUR(visit_date), '##:00:00')?

    – user50710
    Nov 20 '18 at 2:19











  • Hour(visit_date)/8 should give 0 1 or 2, so I think you'll need to multiply it by 8 again to get 0 8 or 16 and format(.., '00":00:00"') - FORMAT obeys the .net formatting system so any literal text is surrounded by speech marks, the first 00 being used to pad the number out to double digits

    – Caius Jard
    Nov 20 '18 at 7:19













  • That being said, you could alternatively date_add your (hour(visit_date)/8)*8 hours to your cast(visit_date as date) (midnight) if you want to keep it as a datetime or work with it further

    – Caius Jard
    Nov 20 '18 at 7:25











  • Added a second query implementing the above

    – Caius Jard
    Nov 20 '18 at 8:56





















0














Use a cross apply to form 4 shift boundary values, then use those in a case expression to genertate the group by values



SELECT
case
when visit_date >= s1 and visit_date < s2 then s1
when visit_date >= s2 and visit_date < s3 then s2
when visit_date >= s3 and visit_date < s4 then s3
end as shift
, count(1) as count
FROM mytable
CROSS APPLY (
select
cast(CAST(visit_date as DATE)as datetime) s1
, dateadd(hh,8,cast(CAST(visit_date as DATE)as datetime)) s2
, dateadd(hh,16,cast(CAST(visit_date as DATE)as datetime)) s3
, dateadd(hh,24,cast(CAST(visit_date as DATE)as datetime)) s4
) ca
GROUP BY
case
when visit_date >= s1 and visit_date < s2 then s1
when visit_date >= s2 and visit_date < s3 then s2
when visit_date >= s3 and visit_date < s4 then s3
end
ORDER BY shift


result:



+----+---------------------+-------+
| | shift | count |
+----+---------------------+-------+
| 1 | 01.11.2010 00:00:00 | 1 |
| 2 | 01.11.2010 08:00:00 | 1 |
| 3 | 01.11.2010 16:00:00 | 1 |
| 4 | 02.11.2010 00:00:00 | 1 |
| 5 | 02.11.2010 08:00:00 | 1 |
| 6 | 02.11.2010 16:00:00 | 1 |
| 7 | 03.11.2010 00:00:00 | 2 |
| 8 | 03.11.2010 08:00:00 | 1 |
+----+---------------------+-------+





share|improve this answer































    0














    I think the canonical way in SQL Server is to use dateadd() and datediff():



    select dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3)) as day_hour8,
    count(*)
    from t
    group by dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3))
    order by day_hour8;





    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383471%2fhow-to-group-and-count-by-date-and-8-hr-interval-on-those-dates-in-datetime-sql%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2














      Add the hours in to what you group and count:



      SELECT 
      CAST(visit_date as DATE),
      HOUR(visit_date)/8 as ival8h
      count(1) as count
      FROM table
      GROUP BY CAST(visit_date as DATE), HOUR(visit_date)/8
      ORDER BY CAST(visit_date as DATE)


      The hour function returns the hour number of the passed date, divide it by 8 to get an int of the interval, so 0 to 7 becomes 0, 8 to 16 becomes 1 etc



      If you want it back as a time pegged to a round 8h multiply it by 8 again and format it to NN:00:00, or add it to the date, thus:



      SELECT 
      DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME) as quantized_date,
      count(1) as count
      FROM table
      GROUP BY DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME)
      ORDER BY CAST(visit_date as DATE)


      This basically rounds the hours down to the lesser 8h market and adds that to midnight. Two casts are required (probably) on the date because DATEADD won't add hours to a date, only a datetime but we need the cast to date to peg the tine element to midnight



      If you want there to be a date and a 0 count for periods where no events took place, use a numbers table or row generator and create a sequence of dates to left join your real data onto, then count the real data grouped by the fake dates






      share|improve this answer


























      • Thanks, this makes a lot of sense. To reformat it, would I simply substitute HOUR(visit_date)/8 as ival8h with FORMAT(HOUR(visit_date), '##:00:00')?

        – user50710
        Nov 20 '18 at 2:19











      • Hour(visit_date)/8 should give 0 1 or 2, so I think you'll need to multiply it by 8 again to get 0 8 or 16 and format(.., '00":00:00"') - FORMAT obeys the .net formatting system so any literal text is surrounded by speech marks, the first 00 being used to pad the number out to double digits

        – Caius Jard
        Nov 20 '18 at 7:19













      • That being said, you could alternatively date_add your (hour(visit_date)/8)*8 hours to your cast(visit_date as date) (midnight) if you want to keep it as a datetime or work with it further

        – Caius Jard
        Nov 20 '18 at 7:25











      • Added a second query implementing the above

        – Caius Jard
        Nov 20 '18 at 8:56


















      2














      Add the hours in to what you group and count:



      SELECT 
      CAST(visit_date as DATE),
      HOUR(visit_date)/8 as ival8h
      count(1) as count
      FROM table
      GROUP BY CAST(visit_date as DATE), HOUR(visit_date)/8
      ORDER BY CAST(visit_date as DATE)


      The hour function returns the hour number of the passed date, divide it by 8 to get an int of the interval, so 0 to 7 becomes 0, 8 to 16 becomes 1 etc



      If you want it back as a time pegged to a round 8h multiply it by 8 again and format it to NN:00:00, or add it to the date, thus:



      SELECT 
      DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME) as quantized_date,
      count(1) as count
      FROM table
      GROUP BY DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME)
      ORDER BY CAST(visit_date as DATE)


      This basically rounds the hours down to the lesser 8h market and adds that to midnight. Two casts are required (probably) on the date because DATEADD won't add hours to a date, only a datetime but we need the cast to date to peg the tine element to midnight



      If you want there to be a date and a 0 count for periods where no events took place, use a numbers table or row generator and create a sequence of dates to left join your real data onto, then count the real data grouped by the fake dates






      share|improve this answer


























      • Thanks, this makes a lot of sense. To reformat it, would I simply substitute HOUR(visit_date)/8 as ival8h with FORMAT(HOUR(visit_date), '##:00:00')?

        – user50710
        Nov 20 '18 at 2:19











      • Hour(visit_date)/8 should give 0 1 or 2, so I think you'll need to multiply it by 8 again to get 0 8 or 16 and format(.., '00":00:00"') - FORMAT obeys the .net formatting system so any literal text is surrounded by speech marks, the first 00 being used to pad the number out to double digits

        – Caius Jard
        Nov 20 '18 at 7:19













      • That being said, you could alternatively date_add your (hour(visit_date)/8)*8 hours to your cast(visit_date as date) (midnight) if you want to keep it as a datetime or work with it further

        – Caius Jard
        Nov 20 '18 at 7:25











      • Added a second query implementing the above

        – Caius Jard
        Nov 20 '18 at 8:56
















      2












      2








      2







      Add the hours in to what you group and count:



      SELECT 
      CAST(visit_date as DATE),
      HOUR(visit_date)/8 as ival8h
      count(1) as count
      FROM table
      GROUP BY CAST(visit_date as DATE), HOUR(visit_date)/8
      ORDER BY CAST(visit_date as DATE)


      The hour function returns the hour number of the passed date, divide it by 8 to get an int of the interval, so 0 to 7 becomes 0, 8 to 16 becomes 1 etc



      If you want it back as a time pegged to a round 8h multiply it by 8 again and format it to NN:00:00, or add it to the date, thus:



      SELECT 
      DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME) as quantized_date,
      count(1) as count
      FROM table
      GROUP BY DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME)
      ORDER BY CAST(visit_date as DATE)


      This basically rounds the hours down to the lesser 8h market and adds that to midnight. Two casts are required (probably) on the date because DATEADD won't add hours to a date, only a datetime but we need the cast to date to peg the tine element to midnight



      If you want there to be a date and a 0 count for periods where no events took place, use a numbers table or row generator and create a sequence of dates to left join your real data onto, then count the real data grouped by the fake dates






      share|improve this answer















      Add the hours in to what you group and count:



      SELECT 
      CAST(visit_date as DATE),
      HOUR(visit_date)/8 as ival8h
      count(1) as count
      FROM table
      GROUP BY CAST(visit_date as DATE), HOUR(visit_date)/8
      ORDER BY CAST(visit_date as DATE)


      The hour function returns the hour number of the passed date, divide it by 8 to get an int of the interval, so 0 to 7 becomes 0, 8 to 16 becomes 1 etc



      If you want it back as a time pegged to a round 8h multiply it by 8 again and format it to NN:00:00, or add it to the date, thus:



      SELECT 
      DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME) as quantized_date,
      count(1) as count
      FROM table
      GROUP BY DATEADD(hour, (HOUR(visit_date)/8)*8, CAST(CAST(visit_date as DATE) as DATETIME)
      ORDER BY CAST(visit_date as DATE)


      This basically rounds the hours down to the lesser 8h market and adds that to midnight. Two casts are required (probably) on the date because DATEADD won't add hours to a date, only a datetime but we need the cast to date to peg the tine element to midnight



      If you want there to be a date and a 0 count for periods where no events took place, use a numbers table or row generator and create a sequence of dates to left join your real data onto, then count the real data grouped by the fake dates







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Nov 20 '18 at 8:56

























      answered Nov 19 '18 at 23:27









      Caius JardCaius Jard

      11.6k21239




      11.6k21239













      • Thanks, this makes a lot of sense. To reformat it, would I simply substitute HOUR(visit_date)/8 as ival8h with FORMAT(HOUR(visit_date), '##:00:00')?

        – user50710
        Nov 20 '18 at 2:19











      • Hour(visit_date)/8 should give 0 1 or 2, so I think you'll need to multiply it by 8 again to get 0 8 or 16 and format(.., '00":00:00"') - FORMAT obeys the .net formatting system so any literal text is surrounded by speech marks, the first 00 being used to pad the number out to double digits

        – Caius Jard
        Nov 20 '18 at 7:19













      • That being said, you could alternatively date_add your (hour(visit_date)/8)*8 hours to your cast(visit_date as date) (midnight) if you want to keep it as a datetime or work with it further

        – Caius Jard
        Nov 20 '18 at 7:25











      • Added a second query implementing the above

        – Caius Jard
        Nov 20 '18 at 8:56





















      • Thanks, this makes a lot of sense. To reformat it, would I simply substitute HOUR(visit_date)/8 as ival8h with FORMAT(HOUR(visit_date), '##:00:00')?

        – user50710
        Nov 20 '18 at 2:19











      • Hour(visit_date)/8 should give 0 1 or 2, so I think you'll need to multiply it by 8 again to get 0 8 or 16 and format(.., '00":00:00"') - FORMAT obeys the .net formatting system so any literal text is surrounded by speech marks, the first 00 being used to pad the number out to double digits

        – Caius Jard
        Nov 20 '18 at 7:19













      • That being said, you could alternatively date_add your (hour(visit_date)/8)*8 hours to your cast(visit_date as date) (midnight) if you want to keep it as a datetime or work with it further

        – Caius Jard
        Nov 20 '18 at 7:25











      • Added a second query implementing the above

        – Caius Jard
        Nov 20 '18 at 8:56



















      Thanks, this makes a lot of sense. To reformat it, would I simply substitute HOUR(visit_date)/8 as ival8h with FORMAT(HOUR(visit_date), '##:00:00')?

      – user50710
      Nov 20 '18 at 2:19





      Thanks, this makes a lot of sense. To reformat it, would I simply substitute HOUR(visit_date)/8 as ival8h with FORMAT(HOUR(visit_date), '##:00:00')?

      – user50710
      Nov 20 '18 at 2:19













      Hour(visit_date)/8 should give 0 1 or 2, so I think you'll need to multiply it by 8 again to get 0 8 or 16 and format(.., '00":00:00"') - FORMAT obeys the .net formatting system so any literal text is surrounded by speech marks, the first 00 being used to pad the number out to double digits

      – Caius Jard
      Nov 20 '18 at 7:19







      Hour(visit_date)/8 should give 0 1 or 2, so I think you'll need to multiply it by 8 again to get 0 8 or 16 and format(.., '00":00:00"') - FORMAT obeys the .net formatting system so any literal text is surrounded by speech marks, the first 00 being used to pad the number out to double digits

      – Caius Jard
      Nov 20 '18 at 7:19















      That being said, you could alternatively date_add your (hour(visit_date)/8)*8 hours to your cast(visit_date as date) (midnight) if you want to keep it as a datetime or work with it further

      – Caius Jard
      Nov 20 '18 at 7:25





      That being said, you could alternatively date_add your (hour(visit_date)/8)*8 hours to your cast(visit_date as date) (midnight) if you want to keep it as a datetime or work with it further

      – Caius Jard
      Nov 20 '18 at 7:25













      Added a second query implementing the above

      – Caius Jard
      Nov 20 '18 at 8:56







      Added a second query implementing the above

      – Caius Jard
      Nov 20 '18 at 8:56















      0














      Use a cross apply to form 4 shift boundary values, then use those in a case expression to genertate the group by values



      SELECT
      case
      when visit_date >= s1 and visit_date < s2 then s1
      when visit_date >= s2 and visit_date < s3 then s2
      when visit_date >= s3 and visit_date < s4 then s3
      end as shift
      , count(1) as count
      FROM mytable
      CROSS APPLY (
      select
      cast(CAST(visit_date as DATE)as datetime) s1
      , dateadd(hh,8,cast(CAST(visit_date as DATE)as datetime)) s2
      , dateadd(hh,16,cast(CAST(visit_date as DATE)as datetime)) s3
      , dateadd(hh,24,cast(CAST(visit_date as DATE)as datetime)) s4
      ) ca
      GROUP BY
      case
      when visit_date >= s1 and visit_date < s2 then s1
      when visit_date >= s2 and visit_date < s3 then s2
      when visit_date >= s3 and visit_date < s4 then s3
      end
      ORDER BY shift


      result:



      +----+---------------------+-------+
      | | shift | count |
      +----+---------------------+-------+
      | 1 | 01.11.2010 00:00:00 | 1 |
      | 2 | 01.11.2010 08:00:00 | 1 |
      | 3 | 01.11.2010 16:00:00 | 1 |
      | 4 | 02.11.2010 00:00:00 | 1 |
      | 5 | 02.11.2010 08:00:00 | 1 |
      | 6 | 02.11.2010 16:00:00 | 1 |
      | 7 | 03.11.2010 00:00:00 | 2 |
      | 8 | 03.11.2010 08:00:00 | 1 |
      +----+---------------------+-------+





      share|improve this answer




























        0














        Use a cross apply to form 4 shift boundary values, then use those in a case expression to genertate the group by values



        SELECT
        case
        when visit_date >= s1 and visit_date < s2 then s1
        when visit_date >= s2 and visit_date < s3 then s2
        when visit_date >= s3 and visit_date < s4 then s3
        end as shift
        , count(1) as count
        FROM mytable
        CROSS APPLY (
        select
        cast(CAST(visit_date as DATE)as datetime) s1
        , dateadd(hh,8,cast(CAST(visit_date as DATE)as datetime)) s2
        , dateadd(hh,16,cast(CAST(visit_date as DATE)as datetime)) s3
        , dateadd(hh,24,cast(CAST(visit_date as DATE)as datetime)) s4
        ) ca
        GROUP BY
        case
        when visit_date >= s1 and visit_date < s2 then s1
        when visit_date >= s2 and visit_date < s3 then s2
        when visit_date >= s3 and visit_date < s4 then s3
        end
        ORDER BY shift


        result:



        +----+---------------------+-------+
        | | shift | count |
        +----+---------------------+-------+
        | 1 | 01.11.2010 00:00:00 | 1 |
        | 2 | 01.11.2010 08:00:00 | 1 |
        | 3 | 01.11.2010 16:00:00 | 1 |
        | 4 | 02.11.2010 00:00:00 | 1 |
        | 5 | 02.11.2010 08:00:00 | 1 |
        | 6 | 02.11.2010 16:00:00 | 1 |
        | 7 | 03.11.2010 00:00:00 | 2 |
        | 8 | 03.11.2010 08:00:00 | 1 |
        +----+---------------------+-------+





        share|improve this answer


























          0












          0








          0







          Use a cross apply to form 4 shift boundary values, then use those in a case expression to genertate the group by values



          SELECT
          case
          when visit_date >= s1 and visit_date < s2 then s1
          when visit_date >= s2 and visit_date < s3 then s2
          when visit_date >= s3 and visit_date < s4 then s3
          end as shift
          , count(1) as count
          FROM mytable
          CROSS APPLY (
          select
          cast(CAST(visit_date as DATE)as datetime) s1
          , dateadd(hh,8,cast(CAST(visit_date as DATE)as datetime)) s2
          , dateadd(hh,16,cast(CAST(visit_date as DATE)as datetime)) s3
          , dateadd(hh,24,cast(CAST(visit_date as DATE)as datetime)) s4
          ) ca
          GROUP BY
          case
          when visit_date >= s1 and visit_date < s2 then s1
          when visit_date >= s2 and visit_date < s3 then s2
          when visit_date >= s3 and visit_date < s4 then s3
          end
          ORDER BY shift


          result:



          +----+---------------------+-------+
          | | shift | count |
          +----+---------------------+-------+
          | 1 | 01.11.2010 00:00:00 | 1 |
          | 2 | 01.11.2010 08:00:00 | 1 |
          | 3 | 01.11.2010 16:00:00 | 1 |
          | 4 | 02.11.2010 00:00:00 | 1 |
          | 5 | 02.11.2010 08:00:00 | 1 |
          | 6 | 02.11.2010 16:00:00 | 1 |
          | 7 | 03.11.2010 00:00:00 | 2 |
          | 8 | 03.11.2010 08:00:00 | 1 |
          +----+---------------------+-------+





          share|improve this answer













          Use a cross apply to form 4 shift boundary values, then use those in a case expression to genertate the group by values



          SELECT
          case
          when visit_date >= s1 and visit_date < s2 then s1
          when visit_date >= s2 and visit_date < s3 then s2
          when visit_date >= s3 and visit_date < s4 then s3
          end as shift
          , count(1) as count
          FROM mytable
          CROSS APPLY (
          select
          cast(CAST(visit_date as DATE)as datetime) s1
          , dateadd(hh,8,cast(CAST(visit_date as DATE)as datetime)) s2
          , dateadd(hh,16,cast(CAST(visit_date as DATE)as datetime)) s3
          , dateadd(hh,24,cast(CAST(visit_date as DATE)as datetime)) s4
          ) ca
          GROUP BY
          case
          when visit_date >= s1 and visit_date < s2 then s1
          when visit_date >= s2 and visit_date < s3 then s2
          when visit_date >= s3 and visit_date < s4 then s3
          end
          ORDER BY shift


          result:



          +----+---------------------+-------+
          | | shift | count |
          +----+---------------------+-------+
          | 1 | 01.11.2010 00:00:00 | 1 |
          | 2 | 01.11.2010 08:00:00 | 1 |
          | 3 | 01.11.2010 16:00:00 | 1 |
          | 4 | 02.11.2010 00:00:00 | 1 |
          | 5 | 02.11.2010 08:00:00 | 1 |
          | 6 | 02.11.2010 16:00:00 | 1 |
          | 7 | 03.11.2010 00:00:00 | 2 |
          | 8 | 03.11.2010 08:00:00 | 1 |
          +----+---------------------+-------+






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 19 '18 at 23:20









          Used_By_AlreadyUsed_By_Already

          23k21938




          23k21938























              0














              I think the canonical way in SQL Server is to use dateadd() and datediff():



              select dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3)) as day_hour8,
              count(*)
              from t
              group by dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3))
              order by day_hour8;





              share|improve this answer




























                0














                I think the canonical way in SQL Server is to use dateadd() and datediff():



                select dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3)) as day_hour8,
                count(*)
                from t
                group by dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3))
                order by day_hour8;





                share|improve this answer


























                  0












                  0








                  0







                  I think the canonical way in SQL Server is to use dateadd() and datediff():



                  select dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3)) as day_hour8,
                  count(*)
                  from t
                  group by dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3))
                  order by day_hour8;





                  share|improve this answer













                  I think the canonical way in SQL Server is to use dateadd() and datediff():



                  select dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3)) as day_hour8,
                  count(*)
                  from t
                  group by dateadd(hour, 0, 3 * (datediff(hour, 0, visit_date) / 3))
                  order by day_hour8;






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 20 '18 at 3:04









                  Gordon LinoffGordon Linoff

                  769k35303404




                  769k35303404






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53383471%2fhow-to-group-and-count-by-date-and-8-hr-interval-on-those-dates-in-datetime-sql%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Biblatex bibliography style without URLs when DOI exists (in Overleaf with Zotero bibliography)

                      ComboBox Display Member on multiple fields

                      Is it possible to collect Nectar points via Trainline?