วิธีจัดกลุ่มตามชั่วโมงหรือ 10 นาที


167

เช่นเมื่อฉันทำ

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date]

ฉันจะระบุช่วงเวลากลุ่มได้อย่างไร

MS SQL 2008

2nd แก้ไข

ฉันกำลังพยายาม

SELECT MIN([Date]) AS RecT, AVG(Value)
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY (DATEPART(MINUTE, [Date]) / 10)
  ORDER BY RecT

เปลี่ยน% 10 เป็น / 10 เป็นไปได้ไหมที่จะสร้างเอาต์พุตวันที่โดยไม่มีมิลลิวินาที?

คำตอบ:


214

ในที่สุดก็ทำได้ด้วย

GROUP BY
DATEPART(YEAR, DT.[Date]),
DATEPART(MONTH, DT.[Date]),
DATEPART(DAY, DT.[Date]),
DATEPART(HOUR, DT.[Date]),
(DATEPART(MINUTE, DT.[Date]) / 10)

11
ฉันทำมันROUND((DATEPART(MINUTE, DT.[Date]) / 5),0,1) * 5เพื่อที่ว่าเมื่อฉันดูข้อมูลมันมีความสัมพันธ์กับช่วงเวลาที่ใกล้ที่สุด
hdost

7
สามารถปรับปีเดือนและวันให้DATE(DT.[Date])เป็น

@ Keelan ใช้งานไม่ได้สำหรับฉัน - อย่างไรก็ตาม CONVERT (วันที่, DT. [วันที่]) ทำ
Dan Parsonson

datepart(hour, workingPolicy.workingHours)/2.0ให้1.5ในขณะที่datepart(hour, '1900-01-01 09:00:30.000')/2.0ให้4.5ฉันไม่เข้าใจว่าทำไม หมายเหตุ: workingPolicy.workingHours = 1900-01-01 09: โปรดช่วย
affanBajwa

65

ฉันไปงานปาร์ตี้ช้าสุด ๆ แต่สิ่งนี้ไม่ปรากฏในคำตอบที่มีอยู่:

GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', date_column) / 10 * 10, '2000')
  • 10และMINUTEเงื่อนไขสามารถเปลี่ยนเป็นจำนวนใด ๆ และDATEPARTตามลำดับ
  • มันเป็นDATETIMEค่าซึ่งหมายความว่า:
    • มันทำงานได้ดีในช่วงเวลานาน (ไม่มีการชนกันระหว่างปี)
    • การรวมไว้ในSELECTคำสั่งจะให้คอลัมน์ผลลัพธ์ของคุณด้วยเอาต์พุตที่ถูกตัดทอนในระดับที่คุณระบุ
  • '2000'เป็น "จุดยึดวันที่" ซึ่ง SQL จะทำการคำนวณวันที่ Jereonh ค้นพบด้านล่างว่าคุณพบจำนวนเต็มล้นกับจุดยึดก่อนหน้า ( 0) เมื่อคุณจัดกลุ่มวันที่ล่าสุดตามวินาทีหรือมิลลิวินาที
SELECT   DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
                                                               AS [date_truncated],
         COUNT(*) AS [records_in_interval],
         AVG(aa.[value]) AS [average_value]
FROM     [friib].[dbo].[archive_analog] AS aa
GROUP BY DATEADD(MINUTE, DATEDIFF(MINUTE, '2000', aa.[date]) / 10 * 10, '2000')
ORDER BY [date_truncated]

ถ้าข้อมูลของคุณช่วงศตวรรษใช้วันที่สมอเดียวสำหรับสองหรือมิลลิวินาทีการจัดกลุ่มจะยังคงพบล้น หากสิ่งนั้นเกิดขึ้นคุณสามารถขอให้แต่ละแถวยึดการเปรียบเทียบการ binning กับเที่ยงคืนของวันที่:

  • ใช้DATEADD(DAY, DATEDIFF(DAY, 0, aa.[date]), 0)แทน'2000'ตำแหน่งที่ปรากฏด้านบน ข้อความค้นหาของคุณจะไม่สามารถอ่านได้ทั้งหมด แต่จะใช้งานได้

  • ทางเลือกอื่นอาจCONVERT(DATETIME, CONVERT(DATE, aa.[date]))เป็นการทดแทน

2 32 ≈ 4.29E + 9 ดังนั้นหากคุณDATEPARTมีที่SECONDคุณจะได้รับ 4300000000 วินาทีด้านใดด้านหนึ่งหรือ "สมอ± 136 ปี." ในทำนองเดียวกัน 2 32มิลลิวินาทีเป็น≈ 49.7 วัน
หากข้อมูลของคุณครอบคลุมหลายศตวรรษหรือพันปีและยังคงถูกต้องถึงที่สองหรือมิลลิวินาที…ขอแสดงความยินดี! ไม่ว่าคุณจะทำอะไร


เป็นไปได้ไหมที่จะทำสิ่งนี้จากวันที่เริ่มต้นที่เฉพาะเจาะจง
Pylander

1
@pylander แน่นอน เพียงแค่ใส่ประโยคก่อนwhere group by
ไมเคิล - ที่ไหน Clay Shirky

2
ฉันเห็น. ดังนั้นการเปลี่ยนแปลงนี้/ 20 * 20จะเหมือนกับการรวบรวมข้อมูลเป็นระยะเวลา 20 นาทีหรือไม่ ขออภัยฉันกำลังดิ้นรนเพื่อคณิตศาสตร์ในตอนนี้
ลำเอียง

2
สำหรับวินาทีในฐานะ DATEPART ฉันได้รับข้อความแสดงข้อผิดพลาด ( The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.) ดูเหมือนว่า MINUTE เป็นส่วนที่เล็กที่สุดที่คุณสามารถใช้กับวิธีนี้
jeroenh

1
@ jeroenh คุณถูกต้อง ฉันได้เพิ่มหัวข้อเพื่อพูดคุยเกี่ยวกับเรื่องนั้น TLDR: เปลี่ยน0ไป'2000'(! คำพูดที่มีความสำคัญ) แล้วลองSECONDอีกครั้ง
ไมเคิล - Clay Shirky อยู่ที่ไหน

17

ใน T-SQL คุณสามารถ:

SELECT [Date]
  FROM [FRIIB].[dbo].[ArchiveAnalog]
  GROUP BY [Date], DATEPART(hh, [Date])

หรือ

โดยการใช้งานนาที DATEPART(mi, [Date])

หรือ

ใช้งาน 10 นาทีDATEPART(mi, [Date]) / 10(เช่นแนะนำทิโมธี)


1
จัดกลุ่มตาม [วันที่] DATEPART (hh, [วันที่]) ยุ่งเหยิงใช่ไหม
cnd

1
@nCdy น่าจะใช้ได้ไม่งั้นคุณจะได้รับข้อผิดพลาด "... ไม่ถูกต้องในรายการที่เลือกเพราะมันไม่ได้อยู่ในฟังก์ชั่นรวมหรือกลุ่มตามข้อ"
tzup

1
คุณจัดกลุ่มตามวันที่และชั่วโมงในเวลาเดียวกันได้อย่างไร ฉันแค่ใช้วันที่ขั้นต่ำ
cnd

หากคุณใช้ Min (Date) แน่นอนว่าคุณสามารถใช้ Date ในกลุ่ม By
tzup

3
นาทีหารด้วย 10 จะสร้างการจัดกลุ่มตามช่วงเวลา 10 นาทีซึ่งฉันต้องการ Modulo 10 ไม่มีเหตุผล
Tar

12

สำหรับช่วงเวลา 10 นาทีคุณจะ

GROUP BY (DATEPART(MINUTE, [Date]) / 10)

ตามที่ถูกกล่าวถึงแล้วโดย tzup และ Pieter888 ... เพื่อทำช่วงเวลาหนึ่งชั่วโมงเพียงแค่

GROUP BY DATEPART(HOUR, [Date])

2
แต่ที่นี่ฉันจัดกลุ่มนาทีของปี 1980 กับนาทีของปี 2011: SI จำเป็นต้องใส่ใจกับมัน
cnd

% จะเป็นคณิตศาสตร์ที่ถูกต้องหรือไม่ จะไม่สร้าง 10 กลุ่ม ตัวอย่างเช่น: 1% 10 = 9 2% 10 = 8 ไม่จำเป็นว่าจะเป็นการจัดกลุ่มตามลำดับเวลาที่ถูกต้องเช่นกัน ฉันคิดว่าแค่การหารปกติจะถูกต้อง เว้นแต่ว่า% จะไม่เหลือตัวหารใน sql
Steven

12
นาทีหารด้วย 10 จะสร้างการจัดกลุ่มตามช่วงเวลา 10 นาทีซึ่งฉันต้องการ Modulo 10 ไม่มีเหตุผล
Tar

ตกลงกับทาร์ การจัดกลุ่มไม่สมเหตุสมผล
MikeMurko

7

ควรเป็นสิ่งที่ชอบ

select timeslot, count(*)  
from 
    (
    select datepart('hh', date) timeslot
    FROM [FRIIB].[dbo].[ArchiveAnalog]  
    ) 
group by timeslot

(ไม่แน่ใจ 100% เกี่ยวกับไวยากรณ์ - ฉันเป็นคนประเภท Oracle มากกว่า)

ใน Oracle:

SELECT timeslot, COUNT(*) 
FROM
(  
    SELECT to_char(l_time, 'YYYY-MM-DD hh24') timeslot 
    FROM
    (
        SELECT l_time FROM mytab  
    )  
) GROUP BY timeslot 

6

คำตอบดั้งเดิมที่ผู้เขียนมอบให้นั้นใช้ได้ค่อนข้างดี เพียงเพื่อขยายแนวคิดนี้คุณสามารถทำสิ่งที่ชอบ

group by datediff(minute, 0, [Date])/10

ซึ่งจะช่วยให้คุณสามารถจัดกลุ่มตามระยะเวลานานกว่านั้น 60 นาทีพูด 720 ซึ่งครึ่งวัน ฯลฯ


1
สิ่งที่จะเป็นแบบสอบถาม MySQL สำหรับข้างต้น?
Biranchi


1

ทางออกของฉันคือการใช้ฟังก์ชั่นเพื่อสร้างตารางที่มีช่วงวันที่จากนั้นเข้าร่วมตารางนี้กับข้อมูลที่ฉันต้องการจัดกลุ่มโดยใช้ช่วงวันที่ในตาราง ช่วงวันที่นั้นจะสามารถเลือกได้ง่ายเมื่อนำเสนอข้อมูล

CREATE FUNCTION [dbo].[fn_MinuteIntervals]
    (
      @startDate SMALLDATETIME ,
      @endDate SMALLDATETIME ,
      @interval INT = 1
    )
RETURNS @returnDates TABLE
    (
      [date] SMALLDATETIME PRIMARY KEY NOT NULL
    )
AS
    BEGIN
        DECLARE @counter SMALLDATETIME
        SET @counter = @startDate
        WHILE @counter <= @endDate
            BEGIN
                INSERT INTO @returnDates VALUES ( @counter )
                SET @counter = DATEADD(n, @interval, @counter)
            END
        RETURN
    END

1
declare @interval tinyint
set @interval = 30
select dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0), sum(Value_Transaction)
from Transactions
group by dateadd(minute,(datediff(minute,0,[DateInsert])/@interval)*@interval,0)

8
ยินดีต้อนรับสู่ stackoverflow คุณต้องอธิบายคำตอบของคุณอย่างเต็มที่และสิ่งนี้จะเพิ่มอะไรกับ 10 คำตอบอื่น ๆ บนเว็บไซต์
Simon.SA

0

สำหรับ SQL Server 2012 ถึงแม้ว่าฉันเชื่อว่าจะใช้งานได้ใน SQL Server 2008R2 แต่ฉันใช้วิธีการต่อไปนี้เพื่อแบ่งเวลาเป็นมิลลิวินาที:

DATEADD(MILLISECOND, -DATEDIFF(MILLISECOND, CAST(time AS DATE), time) % @msPerSlice, time)

สิ่งนี้ทำงานโดย:

  • รับจำนวนมิลลิวินาทีระหว่างจุดคงที่และเวลาเป้าหมาย:
    @ms = DATEDIFF(MILLISECOND, CAST(time AS DATE), time)
  • การแบ่งส่วนที่เหลือของมิลลิวินาทีเหล่านั้นออกเป็นส่วนเวลา:
    @rms = @ms % @msPerSlice
  • การเพิ่มค่าลบของส่วนที่เหลือให้กับเวลาเป้าหมายเพื่อรับเวลาส่วนแบ่ง:
    DATEADD(MILLISECOND, -@rms, time)

โชคไม่ดีที่กระแสข้อมูลที่มีหน่วยเป็นไมโครวินาทีและหน่วยที่เล็กกว่านี้ชุดข้อมูลที่ใหญ่กว่าจึงจำเป็นต้องใช้จุดคงที่ที่สะดวกกว่า

ฉันไม่ได้ทำการเปรียบเทียบอย่างจริงจังและฉันไม่ได้อยู่ในข้อมูลขนาดใหญ่ดังนั้นระยะของคุณอาจแตกต่างกันไป แต่ประสิทธิภาพก็ไม่ได้แย่กว่าวิธีอื่น ๆ ที่ลองใช้กับอุปกรณ์และชุดข้อมูลของเราและการจ่ายเงินเพื่อความสะดวกสำหรับนักพัฒนา สำหรับพวกเรา.


0
select from_unixtime( 600 * ( unix_timestamp( [Date] ) % 600 ) ) AS RecT, avg(Value)
from [FRIIB].[dbo].[ArchiveAnalog]
group by RecT
order by RecT;

แทนที่สอง 600 ด้วยจำนวนวินาทีใด ๆ ที่คุณต้องการจัดกลุ่ม

หากคุณต้องการสิ่งนี้บ่อยครั้งและตารางจะไม่เปลี่ยนแปลงดังที่ชื่อไฟล์เก็บถาวรแนะนำอาจเป็นวิธีที่เร็วกว่าในการแปลงและจัดเก็บวันที่ (& เวลา) ในรูปแบบ unixtime ในตาราง


0

ฉันรู้ว่าฉันมาสายกับการแสดงนี้ แต่ฉันใช้มัน - วิธีการที่ค่อนข้างง่าย วิธีนี้ช่วยให้คุณได้รับชิ้นส่วน 60 นาทีโดยไม่มีปัญหาการปัดเศษ

Select 
   CONCAT( 
            Format(endtime,'yyyy-MM-dd_HH:'),  
            LEFT(Format(endtime,'mm'),1),
            '0' 
          ) as [Time-Slice]

0
select dateadd(minute, datediff(minute, 0, Date), 0),
       sum(SnapShotValue)
FROM [FRIIB].[dbo].[ArchiveAnalog]
group by dateadd(minute, datediff(minute, 0, Date), 0)

1
โปรดให้คำอธิบายบางอย่างเมื่อคุณตอบคำถาม
Shizzen83
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.