DateTime을 저장하는 기본 방법


18

날짜 및 시간 정보를 몇 가지 방법으로 저장할 수 있습니다. DateTime 정보를 저장하는 가장 좋은 방법은 무엇입니까?

DateTime ?을 사용하여 두 개의 개별 열 또는 하나의 열에 날짜 및 시간 저장

그 접근법이 왜 더 나은지 설명 할 수 있습니까?

(참고로 MySQL 문서에 링크하십시오. 질문은 MySQL에만 국한되지는 않습니다)
: 날짜 및 시간 형식 날짜 및 시간


3
이는 주로 사용중인 데이터베이스 시스템에 따라 다릅니다. 가치있는 일 : 오라클은이 작업을 하나의 열 (DATETIME 데이터 유형으로)로 선택했습니다. 주어진 검색어에 대해 1 파트가 필요합니다 ... 날짜 또는 시간).
Kris Johnston

5
SQL Server의 경우 분할을 선호하는 경우 날짜별로 그룹화하는 것이 좋습니다. 스트림 집계에서 종합 지수에 대한 일종의없이 사용할 수있을 것 date,time 으로 group by date하지만에 인덱스 datetimegroup by cast(datetime as date)는 원하는 순서를 제공 할 것입니다 비록.
Martin Smith

1
Time 값에 대한 모든 수학은 날짜와 시간대를 알아야합니다. 예를 들어 두 시간 사이의 거리는 DST 이벤트가 포함 된 날, 23 일 또는 25 시간, 윤초도 존재하는지에 따라 달라집니다.
Peteris

답변:


23

데이터를 단일 열에 저장하는 것이 바람직한 방법입니다. 데이터는 불가분의 관계로 연결되어 있기 때문입니다. 특정 시점은 두 가지가 아닌 단일 정보입니다.

많은 제품에서 "장면 뒤에"사용 된 날짜 / 시간 데이터를 저장하는 일반적인 방법은 "날짜"가 10 진수 값의 정수 부분이고 "시간"이 소수 인 10 진수 값으로 변환하는 것입니다. 값. 따라서 1900-01-01 00:00:00은 0.0으로 저장되고 2016 년 9 월 20 일 9:34:00은 42631.39861로 저장됩니다. 42631은 1900-01-01 이후의 일 수입니다. .39861은 자정 이후 경과 된 시간의 일부입니다. 이를 위해 직접 십진법을 사용하지 말고 명시적인 날짜 / 시간 유형을 사용하십시오. 여기의 요점은 단지 예시 일뿐입니다.

데이터를 두 개의 개별 열에 저장하면 주어진 시점이 저장된 값보다 빠르거나 늦은 지 확인하려는 경우 언제든지 두 열 값을 결합해야합니다.

값을 별도로 저장하면 감지하기 어려운 "버그"가 발생하게됩니다. 예를 들면 다음과 같습니다.

IF OBJECT_ID('tempdb..#DT') IS NOT NULL
DROP TABLE #DT;
CREATE TABLE #DT
(
    dt_value DATETIME NOT NULL
    , d_value DATE NOT NULL
    , t_value TIME(0) NOT NULL
);


DECLARE @d DATETIME = '2016-09-20 09:34:00';

INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);

SET @d = '2016-09-20 11:34:00';

INSERT INTO #DT (dt_value, d_value, t_value)
SELECT @d, CONVERT(DATE, @d), CONVERT(TIME(0), @d);

/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.dt_value >= '2016-07-01 11:00:00';

/* show all rows with a date after 2016-07-01 11:00 am */
SELECT *
FROM #DT dt
WHERE dt.d_value >= CONVERT(DATE, '2016-07-01')
    AND dt.t_value >= CONVERT(TIME(0), '11:00:00');

위 코드에서는 테스트 테이블을 만들어 두 값으로 채우고 해당 데이터에 대해 간단한 쿼리를 수행합니다. 첫 번째 SELECT는 두 행을 반환하지만 두 번째 SELECT는 단일 행만 반환하므로 원하는 결과가 아닐 수 있습니다.

여기에 이미지 설명을 입력하십시오

주석에서 @ypercube가 지적한 것처럼 값이 이산 열에있는 날짜 / 시간 범위를 필터링하는 올바른 방법은 다음과 같습니다.

WHERE dt.d_value > CONVERT(DATE, '2016-07-01') /* note there is no time component here */
    OR (
        dt.d_value = CONVERT(DATE, '2016-07-01') 
        AND dt.t_value >= CONVERT(TIME(0), '11:00:00')
    )

분석 목적으로 시간 구성 요소를 분리해야하는 경우 값의 시간 부분에 대해 계산되고 지속되는 열을 추가하는 것을 고려할 수 있습니다.

ALTER TABLE #DT
ADD dt_value_time AS CONVERT(TIME(0), dt_value) PERSISTED;

SELECT *
FROM #dt;

여기에 이미지 설명을 입력하십시오

그런 다음 지속 된 열을 인덱싱하여 시간별로 빠른 정렬 등을 수행 할 수 있습니다.

표시 목적으로 날짜와 시간을 두 필드로 나누는 것을 고려중인 경우 서버가 아닌 클라이언트에서 형식을 지정해야합니다.


11

나는 다른 답변에 반대 의견을 제시 할 것입니다.

날짜 및 시간 구성 요소가 함께 필요한 경우, 즉 하나를 포함하지만 다른 하나는 포함하지 않는 경우 (또는 하나는 NULL이지만 다른 하나는 아닌) 항목이 유효하지 않은 경우, 단일 열에 저장하는 것은 다른 이유에 따라 의미가 있습니다. 답변.

그러나 하나 또는 두 구성 요소가 개별적으로 선택적인 경우 일 수 있습니다 . 이 경우 단일 열에 저장하는 것이 올바르지 않습니다. 그렇게하면 임의의 방식으로 NULL 값을 표시하도록 할 수 있습니다 (예 : 시간을 00:00:00으로 저장).

다음은 몇 가지 예입니다.

  • 마일리지 세금 공제를위한 차량 여행을 기록하고 있습니다. 여행의 정확한 시간을 아는 것이 유용하지만 직원이 메모하지 않고 잊어 버린 경우 날짜는 여전히 자체적으로 기록해야합니다 (필요한 날짜, 선택적 시간).

  • 사람들이 점심을 먹는 시간을 알아보기 위해 설문 조사를 진행하고 있으며 참가자들에게 날짜를 포함하여 점심 시간 샘플이 포함 된 양식을 작성하도록 요청합니다. 일부는 날짜를 채우는 것을 귀찮게하지 않으며, 실제로 관심있는 시간 (선택적 날짜, 필요한 시간)이므로 데이터를 삭제하지 않으려 고합니다.

다른 접근법에 대해서는 이 관련 질문 을 참조하십시오 .


에서 RFC 3339 "지역 알 수없는 오프셋"녹화를위한 규칙이있다. 나는 그것이 "알 수없는 시간"의 유스 케이스를 다루지 않는다고 생각하지만 가깝습니다. 다음 섹션 인 "자격이없는 현지 시간"은 더 가깝지만 다시는 충분하지 않습니다.
geneorama

예, 지금이 때문에 스키마를 리팩터링하는 배럴을 쳐다보고 있습니다. 렌터카 상황에 처하십시오. 렌탈 회사에서 자동차를 픽업하려면 회사가 열려 있어야합니다. 픽업 날짜와 시간을 지정합니다. 그러나 많은 사람들이 키 드롭 박스를 가지고 있습니다. 시간이 지나면 하차합니다 따라서 일요일에 장소가 문을 닫으면; 제거 날짜가 있습니다. 그러나 시간이 아닙니다. 자정까지 일부 위치가 열려 있기 때문에 0 값 (예 : 오전 12시)을 저장하면 작동하지 않습니다. 이는 다른 상황에서 유효한 값입니다.
Reece

5

특정 비즈니스 / 애플리케이션 요구가없는 한 항상 단일 열로 저장하는 것이 좋습니다. 아래는 내 요점입니다-

  • 타임 스탬프에서 시간을 추출하는 것은 문제가되지 않습니다
  • 둘 다 함께 저장할 수 있다면 시간을 위해 여분의 열을 추가해야하는 이유
  • 쿼리 할 때마다 날짜와 시간을 추가하지 마십시오.

1
@a_horse_with_no_name이 여기에 있습니다. 나는 생각한다 "datetimestamp에서 추출 타임 스탬프는 문제가되지 않는다" 로 다시 표현되어야한다 "추출 타임 스탬프 시간하는 것은 문제가되지 않습니다" . "타임 스탬프"는 일반적으로 날짜와 시간 (및 일반적으로 시간대)을 모두 의미합니다.
ypercubeᵀᴹ

예, @ ypercubeᵀᴹ에 동의합니다. 타임 스탬프는 일반적으로 날짜와 시간을 모두 의미합니다. 나는 DateTimeStamp 단어를 명시 적으로 언급 했으므로 누구나 날짜와 시간에 대해 이야기하고 있음을 이해할 수 있습니다. 그러나 당신도 정확합니다. 답을 수정했습니다.
Ashwini Mohan

3

SQL Server에서는 DataTime을 하나의 필드로 저장하는 것이 가장 좋습니다. DataTime 열에서 인덱스를 작성하면 날짜 검색 및 DateTime 검색으로 사용할 수 있습니다. 따라서 특정 날짜에 존재하는 모든 레코드를 제한해야하는 경우 특별한 작업을 수행하지 않아도 인덱스를 계속 사용할 수 있습니다. 시간 부분을 쿼리해야하는 경우 동일한 인덱스를 사용할 수 없으므로 DateTime보다 시간에 더 관심이있는 비즈니스 사례가있는 경우 작성해야하므로 별도로 저장해야합니다. 색인을 작성하고 성능을 향상시킵니다.


1

실제로, 이것은 표준 크로스 DBMS 유형이없는 것이 유감입니다 (INT 및 VARCHAR은 정수 및 문자열 값과 같습니다). 지금까지 만난 두 가지 데이터베이스 간 접근 방식은 VARCHAR / CHAR 열을 사용하여 DataTime 값을 ISO 8601 (더 편리하고 사람이 읽을 수있는) 표준에 따라 형식화 된 문자열로 저장하고 BIGINT를 사용하여 POSIX 타임 스탬프 (더 많은 저장)로 저장하는 것입니다 수학적으로 효율적으로, 더 빠르고, 더 쉽게 조작 할 수 있습니다.


2
그렇습니다. timestamp이것이 바로 SQL 표준이 정의한 것입니다. 타임 스탬프를 문자열로 저장하는 것은 매우 나쁜 조언입니다
a_horse_with_no_name

0

많은 것을 읽은 후에 BIGINT의 UTC Unix 시간이 최적의 솔루션 인 것 같습니다. 필요한 경우 시간대 스토리지에 대해 TZDB 는 VARCHAR에 하나의 ID를 곱합니다. 몇 가지 주장 :

  1. TIMESTAMP 및 DATETIME은 복잡하고 명확하지 않은 백그라운드에서 여러 가지 변칙적 인 변환을 수행합니다. 서버는 현지 시간에서 UTC로 또는 서버 시간으로 또는 그 반대로 또는 때때로 전환됩니다. 모든 기능에 대한 숨겨진 오버 헤드.

  2. BIGINT (8kb)는 xxxxxx.xxxxxx 형식 스토리지에 필요한 DECIMAL보다 가볍거나 가벼우 며, 실제로 MySQL에서는 두 개의 INT + 무언가로 저장됩니다 . 그리고 수세기 전에 저장하기에 충분합니다.

  3. 거의 모든 주요 프로그래밍 언어에는 Unix 시간과 호환되는 표준 함수 라이브러리가 있습니다.

  4. BIGINT를 사용한 수학 연산은 하드웨어의 다른 것보다 빠르거나 빠릅니다.

물론 위의 모든 내용은 대규모 국제 프로젝트와 관련이 있습니다. 작은 것의 경우 선택한 프레임 워크의 기본 형식을 사용하면 충분합니다.


2
" 명확하지 않은 것 같은 배경에서 여러 가지 변칙적 인 변환을 수행합니다. "-어떤 DBMS에 대해 이야기하고 있습니까? A의 timestamp열이 더 "눈길을 끌기 전환"(데이터베이스 계층에서) 및 위해 발생 timestamp with time zone이 잘 문서화하지 않고 (적어도 오라클과 포스트 그레스의 경우) 매뉴얼에 설명되어있다
a_horse_with_no_name

1
"대부분의 모든 주요 프로그래밍 언어에는 Unix 시간과 호환되는 표준 함수 라이브러리가 있습니다." 그럼에도 불구하고 bigint를 사용하여 SQL / DBMS에있는 날짜, 날짜 시간 및 타임 스탬프에 대한 모든 라이브러리와 함수를
버립니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.