ฉันต้องการจัดเก็บเวลาในตารางฐานข้อมูล แต่ต้องจัดเก็บชั่วโมงและนาทีเท่านั้น ฉันรู้ว่าฉันสามารถใช้ DATETIME และเพิกเฉยต่อส่วนประกอบอื่น ๆ ของวันที่ได้ แต่วิธีใดที่ดีที่สุดในการดำเนินการนี้โดยไม่ต้องจัดเก็บข้อมูลมากกว่าที่ฉันต้องการจริงๆ
ฉันต้องการจัดเก็บเวลาในตารางฐานข้อมูล แต่ต้องจัดเก็บชั่วโมงและนาทีเท่านั้น ฉันรู้ว่าฉันสามารถใช้ DATETIME และเพิกเฉยต่อส่วนประกอบอื่น ๆ ของวันที่ได้ แต่วิธีใดที่ดีที่สุดในการดำเนินการนี้โดยไม่ต้องจัดเก็บข้อมูลมากกว่าที่ฉันต้องการจริงๆ
คำตอบ:
คุณสามารถจัดเก็บเป็นจำนวนเต็มของจำนวนนาทีที่ผ่านมาเที่ยงคืน:
เช่น.
0 = 00:00
60 = 01:00
252 = 04:12
อย่างไรก็ตามคุณจะต้องเขียนโค้ดเพื่อสร้างเวลาใหม่ แต่ไม่น่าจะยุ่งยาก
หากคุณกำลังใช้ SQL Server 2008+ ให้พิจารณาTIME
ประเภทข้อมูล บทความ SQLTeamพร้อมตัวอย่างการใช้งานเพิ่มเติม
เริ่ม DATETIME สิ้นสุด DATETIME
ฉันขอให้คุณใช้สองค่า DATETIMEแทนบางสิ่งบางอย่างที่มีข้อความเช่นevent_startและevent_end
เวลาเป็นธุรกิจที่ซับซ้อน
ปัจจุบันโลกส่วนใหญ่ได้นำระบบเมตริกที่ใช้การปฏิเสธมาใช้สำหรับการวัดส่วนใหญ่ไม่ว่าจะถูกหรือผิด นี่เป็นสิ่งที่ดีโดยรวมเพราะอย่างน้อยเราทุกคนสามารถยอมรับได้ว่า ag คือมิลลิลิตรเป็นลูกบาศก์ซม. อย่างน้อยก็ประมาณนั้น ระบบเมตริกมีข้อบกพร่องมากมาย แต่อย่างน้อยก็มีข้อบกพร่องในระดับสากลอย่างต่อเนื่อง
อย่างไรก็ตามเรามีเวลา; 1,000 มิลลิวินาทีในหนึ่งวินาที 60 วินาทีถึงหนึ่งนาที 60 นาทีถึงหนึ่งชั่วโมง 12 ชั่วโมงในแต่ละครึ่งวันประมาณ 30 วันต่อเดือนซึ่งแตกต่างกันไปตามเดือนและปีที่เป็นปัญหาแต่ละประเทศจะมีการชดเชยเวลาจากประเทศอื่น ๆ รูปแบบเวลาในแต่ละประเทศจะแตกต่างกันไป
มันเป็นเรื่องที่ต้องแยกแยะมากมาย แต่ความยาวและสั้นเป็นไปไม่ได้ที่สถานการณ์ที่ซับซ้อนเช่นนี้จะมีวิธีแก้ปัญหาง่ายๆ
บางมุมสามารถตัดได้ แต่มีมุมที่ไม่ควรทำ
แม้ว่าคำตอบด้านบนจะแนะนำให้คุณเก็บจำนวนเต็มของนาทีที่ผ่านมาเที่ยงคืนอาจดูสมเหตุสมผล แต่ฉันได้เรียนรู้ที่จะหลีกเลี่ยงการทำเช่นนั้นด้วยวิธีที่ยาก
เหตุผลในการนำค่า DATETIME สองค่ามาใช้เพื่อเพิ่มความแม่นยำความละเอียดและข้อเสนอแนะ
สิ่งเหล่านี้มีประโยชน์มากเมื่อการออกแบบก่อให้เกิดผลลัพธ์ที่ไม่พึงปรารถนา
ฉันจัดเก็บข้อมูลมากกว่าที่กำหนดหรือไม่
ในตอนแรกอาจดูเหมือนว่ามีการจัดเก็บข้อมูลมากกว่าที่ฉันต้องการ แต่มีเหตุผลที่ดีที่จะรับการโจมตีนี้
การจัดเก็บข้อมูลเพิ่มเติมนี้มักจะช่วยประหยัดเวลาและความพยายามในระยะยาวเพราะฉันพบว่าเมื่อมีคนบอกว่าใช้เวลานานแค่ไหนพวกเขาก็จะอยากรู้ว่าเหตุการณ์นั้นเกิดขึ้นเมื่อใดและที่ไหนเช่นกัน
มันเป็นดาวเคราะห์ขนาดใหญ่
ที่ผ่านมาฉันรู้สึกผิดที่ไม่สนใจว่ามีประเทศอื่น ๆ บนโลกใบนี้นอกเหนือจากตัวฉันเอง ดูเหมือนเป็นความคิดที่ดีในตอนนั้น แต่สิ่งนี้ส่งผลให้เกิดปัญหาปวดหัวและเสียเวลาในภายหลังเสมอ พิจารณาโซนเวลาทั้งหมดเสมอ
ค#
DateTime แสดงผลเป็นอย่างดีกับสตริงใน C # วิธี ToString (รูปแบบสตริง) มีขนาดกะทัดรัดและอ่านง่าย
เช่น
new TimeSpan(EventStart.Ticks - EventEnd.Ticks).ToString("h'h 'm'm 's's'")
เซิร์ฟเวอร์ SQL
นอกจากนี้หากคุณกำลังอ่านฐานข้อมูลของคุณแยกไปยังอินเทอร์เฟซแอปพลิเคชันของคุณ dateTimes เป็นสิ่งที่น่ายินดีที่จะอ่านได้อย่างรวดเร็วและการคำนวณบนฐานข้อมูลนั้นตรงไปตรงมา
เช่น
SELECT DATEDIFF(MINUTE, event_start, event_end)
มาตรฐานวันที่ ISO8601
หากใช้ SQLite แสดงว่าคุณไม่มีสิ่งนี้ให้ใช้ฟิลด์ข้อความแทนและเก็บไว้ในรูปแบบ ISO8601 เช่น
"2013-01-27T12: 30: 00 + 0000"
หมายเหตุ:
ใช้นาฬิกาแบบ 24 ชั่วโมง *
ส่วนชดเชยเวลา (หรือ +0000) ของ ISO8601 จะจับคู่โดยตรงกับค่าลองจิจูดของพิกัด GPS (ไม่คำนึงถึงการปรับเวลาตามฤดูกาลหรือทั่วประเทศ)
เช่น
TimeOffset=(±Longitude.24)/360
... โดยที่±หมายถึงทิศทางตะวันออกหรือตะวันตก
ดังนั้นจึงควรพิจารณาว่าควรเก็บลองจิจูดละติจูดและความสูงพร้อมกับข้อมูลหรือไม่ สิ่งนี้จะแตกต่างกันไปในการใช้งาน
ISO8601 เป็นรูปแบบสากล
วิกิพีเดียเป็นสิ่งที่ดีมากสำหรับรายละเอียดเพิ่มเติมได้ที่http://en.wikipedia.org/wiki/ISO_8601
วันที่และเวลาจะถูกจัดเก็บเป็นเวลาสากลและค่าชดเชยจะถูกบันทึกขึ้นอยู่กับว่าเวลาถูกจัดเก็บไว้ที่ใดในโลก
จากประสบการณ์ของฉันมีความจำเป็นต้องจัดเก็บวันที่และเวลาแบบเต็มเสมอไม่ว่าฉันจะคิดว่าจะมีเมื่อเริ่มโครงการหรือไม่ก็ตาม ISO8601 เป็นวิธีที่ดีมากในอนาคต
คำแนะนำเพิ่มเติมฟรี
นอกจากนี้ยังควรจัดกลุ่มเหตุการณ์เข้าด้วยกันเหมือนห่วงโซ่ เช่นหากบันทึกการแข่งขันเหตุการณ์ทั้งหมดอาจถูกจัดกลุ่มตามนักแข่ง, race_circuit, circuit_checkpoints และ circuit_laps
จากประสบการณ์ของฉันก็ควรระบุด้วยว่าใครเป็นผู้จัดเก็บบันทึก ไม่ว่าจะเป็นตารางที่แยกจากทริกเกอร์หรือเป็นคอลัมน์เพิ่มเติมภายในตารางเดิม
ยิ่งใส่เยอะยิ่งเอาท์
ฉันเข้าใจดีถึงความปรารถนาที่จะประหยัดพื้นที่ให้มากที่สุด แต่ฉันแทบจะไม่ทำเช่นนั้นด้วยการสูญเสียข้อมูล
หลักการทั่วไปเกี่ยวกับฐานข้อมูลก็คือตามที่ชื่อระบุไว้คือฐานข้อมูลสามารถบอกคุณได้มากเท่าที่มีข้อมูลเท่านั้นและอาจมีค่าใช้จ่ายสูงในการย้อนกลับไปดูข้อมูลในอดีตโดยเติมช่องว่าง
วิธีแก้คือต้องทำให้ถูกต้องในครั้งแรก นี่เป็นเรื่องที่พูดง่ายกว่าทำอย่างแน่นอน แต่ตอนนี้คุณควรมีความเข้าใจที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับการออกแบบฐานข้อมูลที่มีประสิทธิภาพและต่อมามีโอกาสที่ดีขึ้นมากในการทำให้ถูกต้องในครั้งแรก
ยิ่งการออกแบบเริ่มต้นของคุณดีขึ้นการซ่อมแซมในภายหลังก็จะมีค่าใช้จ่ายน้อยลง
ฉันแค่พูดทั้งหมดนี้เพราะถ้าฉันย้อนเวลากลับไปได้มันก็คือสิ่งที่ฉันจะบอกตัวเองเมื่อฉันไปถึงที่นั่น
เพียงจัดเก็บวันที่และเวลาปกติและละเว้นสิ่งอื่นใด ทำไมต้องใช้เวลามากขึ้นในการเขียนโค้ดที่โหลด int จัดการและแปลงเป็นวันที่และเวลาในเมื่อคุณสามารถโหลดวันที่และเวลาได้
DATETIME
ประเภทข้อมูลใช้เวลาในการจัดเก็บ 4 ไบต์ในขณะที่SMALLINT
ตัวอย่างเช่นใช้เวลาเพียงหนึ่งในสี่เท่านั้น ไม่มีความแตกต่างอย่างมากหากคุณมีแถวเพียงไม่กี่พันแถว แต่ถ้าคุณมีแถวหลายล้านแถวเหมือนหลาย ๆ บริษัท การประหยัดพื้นที่ของคุณก็จะมาก
เนื่องจากคุณไม่ได้พูดถึงมันเล็กน้อยหากคุณใช้ SQL Server 2008 คุณสามารถใช้ประเภทข้อมูลเวลาหรือใช้นาทีตั้งแต่เที่ยงคืน
SQL Server เก็บเวลาเป็นเศษส่วนของวัน ตัวอย่างเช่น 1 ทั้งวัน = ค่า 1. 12 ชั่วโมงคือค่า 0.5
หากคุณต้องการเก็บค่าเวลาโดยไม่ใช้ประเภท DATETIME การจัดเก็บเวลาในรูปแบบทศนิยมจะเหมาะกับความต้องการนั้นในขณะเดียวกันก็ทำให้การแปลงเป็น DATETIME ทำได้ง่าย
ตัวอย่างเช่น:
SELECT CAST(0.5 AS DATETIME)
--1900-01-01 12:00:00.000
การจัดเก็บค่าเป็น DECIMAL (9,9) จะใช้ 5 ไบต์ อย่างไรก็ตามหากความแม่นยำถึงไม่มีความสำคัญสูงสุด REAL จะใช้เพียง 4 ไบต์ ไม่ว่าในกรณีใดการคำนวณรวม (เช่นเวลาเฉลี่ย) สามารถคำนวณได้อย่างง่ายดายจากค่าตัวเลข แต่ไม่สามารถคำนวณได้ในประเภทข้อมูล / เวลา
ฉันจะแปลงเป็นจำนวนเต็ม (HH * 3600 + MM * 60) และเก็บไว้ในลักษณะนั้น พื้นที่จัดเก็บข้อมูลขนาดเล็กและยังใช้งานได้ง่าย
หากคุณใช้ MySQL ให้ใช้ฟิลด์ประเภท TIME และฟังก์ชันที่เกี่ยวข้องที่มาพร้อมกับ TIME
00:00:00 เป็นรูปแบบเวลามาตรฐาน Unix
หากคุณต้องย้อนกลับไปดูและตรวจสอบตารางด้วยตนเองจำนวนเต็มอาจสร้างความสับสนได้มากกว่าการประทับเวลาจริง
ลอง smalldatetime อาจไม่ได้ให้สิ่งที่คุณต้องการ แต่จะช่วยคุณในอนาคตในการปรับเปลี่ยนวันที่ / เวลา
คุณแน่ใจหรือว่าจะต้องใช้เวลาเพียงชั่วโมงและนาที หากคุณต้องการทำสิ่งใดสิ่งหนึ่งที่มีความหมาย (เช่นตัวอย่างเช่นการคำนวณระยะเวลาระหว่างจุดข้อมูลสองจุดดังกล่าว) ไม่มีข้อมูลเกี่ยวกับเขตเวลาและ DST อาจให้ผลลัพธ์ที่ไม่ถูกต้อง เขตเวลาอาจใช้ไม่ได้ในกรณีของคุณ แต่ DST จะแน่นอนที่สุด
แทนที่จะเป็นนาทีที่ผ่านมา - เที่ยงคืนเราจัดเก็บเป็นนาฬิกา 24 ชั่วโมงเป็น SMALLINT
09:12 = 912 14:15 = 1415
เมื่อแปลงกลับเป็น "รูปแบบที่มนุษย์อ่านได้" เราเพียงแค่ใส่เครื่องหมายจุดคู่ ":" อักขระสองตัวจากทางขวา แป้นด้านซ้ายที่มีศูนย์หากคุณต้องการ บันทึกคณิตศาสตร์ในแต่ละวิธีและใช้จำนวนไบต์น้อยลง (เมื่อเทียบกับ varchar) รวมทั้งบังคับว่าค่าเป็นตัวเลข (แทนที่จะเป็นตัวเลขและตัวอักษร)
ค่อนข้างโง่แม้ว่า ... ควรมีประเภทข้อมูล TIME ใน MS SQL เป็นเวลาหลายปีแล้ว IMHO ...
สิ่งที่ฉันคิดว่าคุณกำลังขอคือตัวแปรที่จะเก็บนาทีเป็นตัวเลข ซึ่งสามารถทำได้ด้วยตัวแปรจำนวนเต็มประเภทต่างๆ:
SELECT 9823754987598 AS MinutesInput
จากนั้นในโปรแกรมของคุณคุณสามารถดูสิ่งนี้ในรูปแบบที่คุณต้องการโดยการคำนวณ:
long MinutesInAnHour = 60;
long MinutesInADay = MinutesInAnHour * 24;
long MinutesInAWeek = MinutesInADay * 7;
long MinutesCalc = long.Parse(rdr["MinutesInput"].toString()); //BigInt converts to long. rdr is an SqlDataReader.
long Weeks = MinutesCalc / MinutesInAWeek;
MinutesCalc -= Weeks * MinutesInAWeek;
long Days = MinutesCalc / MinutesInADay;
MinutesCalc -= Days * MinutesInADay;
long Hours = MinutesCalc / MinutesInAnHour;
MinutesCalc -= Hours * MinutesInAnHour;
long Minutes = MinutesCalc;
ปัญหาเกิดขึ้นเมื่อคุณร้องขอให้ใช้ประสิทธิภาพ แต่ถ้าคุณมีเวลาสั้น ๆใช้ BigInt ที่เป็นโมฆะเพื่อเก็บค่านาทีของคุณ
ค่า null หมายความว่ายังไม่ได้บันทึกเวลา
ตอนนี้ฉันจะอธิบายในรูปแบบของการเดินทางไป - กลับสู่อวกาศ
ขออภัยคอลัมน์ตารางจะเก็บได้เพียงประเภทเดียว ดังนั้นคุณจะต้องสร้างตารางใหม่สำหรับแต่ละประเภทตามที่จำเป็น
ตัวอย่างเช่น:
ถ้า MinutesInput = 0 .. 255 ให้ใช้TinyInt (แปลงตามที่อธิบายไว้ข้างต้น)
ถ้า MinutesInput = 256 .. 131071 ให้ใช้SmallInt (หมายเหตุ: ค่าต่ำสุดของ SmallInt คือ -32,768 ดังนั้นให้ลบและเพิ่ม 32768 เมื่อจัดเก็บและดึงค่าเพื่อใช้เต็มช่วงก่อนที่จะแปลงตามด้านบน)
ถ้า MinutesInput = 131072 .. 8589934591 ให้ใช้Int (หมายเหตุ: ลบและเพิ่ม 2147483648 ตามความจำเป็น)
ถ้า MinutesInput = 8589934592 .. 36893488147419103231 ให้ใช้BigInt (หมายเหตุ: เพิ่มและลบ 9223372036854775808 ตามความจำเป็น)
ถ้า MinutesInput> 36893488147419103231ฉันจะใช้ VARCHAR (X) เป็นการส่วนตัวโดยเพิ่ม X ตามความจำเป็นเนื่องจาก char เป็นไบต์ ฉันจะต้องกลับมาอ่านคำตอบนี้ในภายหลังเพื่ออธิบายสิ่งนี้ทั้งหมด (หรืออาจเป็นเพื่อนร่วมงาน stackoverflowee สามารถตอบคำตอบนี้ให้เสร็จสิ้นได้)
เนื่องจากค่าแต่ละค่าจะต้องใช้คีย์ที่ไม่ซ้ำกันอย่างไม่ต้องสงสัยประสิทธิภาพของฐานข้อมูลจะปรากฏก็ต่อเมื่อช่วงของค่าที่จัดเก็บมีค่าผสมระหว่างค่าน้อยมาก (ใกล้ 0 นาที) และสูงมาก (มากกว่า 8589934591)
จนกว่าค่าที่จัดเก็บจะมีค่ามากกว่า 36893488147419103231 คุณอาจมีคอลัมน์ BigInt เดียวเพื่อแสดงนาทีของคุณเนื่องจากคุณไม่จำเป็นต้องเสีย Int ในตัวระบุที่ไม่ซ้ำกันและ int อื่นเพื่อเก็บค่านาที
การประหยัดเวลาในรูปแบบ UTC สามารถช่วยได้ดีขึ้นตามที่ Kristen แนะนำ
ตรวจสอบให้แน่ใจว่าคุณใช้นาฬิกาแบบ 24 ชม. เนื่องจากไม่มีการใช้ AM หรือ PM เที่ยงใน UTC
ตัวอย่าง:
ยังคงนิยมใช้รูปแบบสี่หลักมาตรฐาน
จัดเก็บticks
เป็น a long
/ bigint
ซึ่งปัจจุบันวัดเป็นมิลลิวินาที คุณสามารถดูค่าที่อัปเดตได้โดยดูที่ไฟล์TimeSpan.TicksPerSecond
ค่า
ฐานข้อมูลส่วนใหญ่มีประเภท DateTime ที่เก็บเวลาโดยอัตโนมัติเป็นเห็บเบื้องหลัง แต่ในกรณีของฐานข้อมูลบางอย่างเช่น SqlLite การจัดเก็บเห็บอาจเป็นวิธีการจัดเก็บวันที่
ภาษาส่วนใหญ่ให้การแปลงได้ง่ายจากTicks
→การ→การTimeSpan
Ticks
ตัวอย่าง
ใน C # รหัสจะเป็น:
long TimeAsTicks = TimeAsTimeSpan.Ticks;
TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);
โปรดทราบว่าเนื่องจากในกรณีของ SqlLite ซึ่งมีประเภทต่างๆเพียงเล็กน้อยเท่านั้นซึ่ง ได้แก่ INT
, REAL
และVARCHAR
มันจะมีความจำเป็นในการจัดเก็บจำนวนเห็บเป็นสตริงหรือสองINT
เซลล์รวม เนื่องจากINT
เป็นหมายเลขที่ลงนาม 32 บิตในขณะที่หมายเลขที่BIGINT
ลงชื่อ 64 บิต
บันทึก
อย่างไรก็ตามความชอบส่วนตัวของฉันคือการจัดเก็บวันที่และเวลาเป็นISO8601
สตริง
IMHO วิธีแก้ปัญหาที่ดีที่สุดขึ้นอยู่กับวิธีการจัดเก็บเวลาในฐานข้อมูลที่เหลือ (และส่วนที่เหลือของแอปพลิเคชันของคุณ)
โดยส่วนตัวแล้วฉันเคยทำงานกับ SQLite และพยายามใช้การประทับเวลาของยูนิกซ์เสมอเพื่อจัดเก็บเวลาที่แน่นอนดังนั้นเมื่อต้องจัดการกับเวลา (เช่นที่คุณขอ) ฉันจะทำสิ่งที่ Glen Solsberry เขียนในคำตอบของเขาและเก็บจำนวนวินาทีไว้ตั้งแต่เที่ยงคืน
เมื่อใช้แนวทางทั่วไปนี้ผู้คน (รวมถึงฉันด้วย!) อ่านโค้ดจะสับสนน้อยลงถ้าฉันใช้มาตรฐานเดียวกันทุกที่