내 데이터베이스 날짜 데이터 유형 십자군 정보 : 유효합니까? 할 보람 있는? 다른 사람이 느끼나요?


13

나는 SO에 대한 SQL 질문에 대답하는 데 많은 시간을 소비합니다. 나는 종종이 ilk에 대한 쿼리를 보게된다.

SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'

SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'

SELECT * FROM person WHERE birthdate BETWEEN 'some string' AND 'other string'

즉, 주어진 매개 변수의 문자열에서 날짜로의 암시 적 변환 (나쁜) 또는 x 백만 개의 데이터베이스 행 값을 문자열로 변환하고 문자열 비교 (걱정)를 수행하는 데이터베이스에 의존

나는 때로는 똑똑한 답변을 작성하지만 실제로 데이터 유형으로 덜 조잡하거나 문자열로 타이핑해야한다고 생각하는 높은 rep 사용자 인 경우 종종 의견을 남깁니다.

주석은 일반적으로 to_date (Oracle), str_to_date (MySQL), convert (SQLSERVER) 또는 이와 유사한 메커니즘을 사용하여 문자열을 날짜로 명시 적으로 변환하면 더 좋을 것입니다.

    --oracle
    SELECT * FROM person WHERE birthdate BETWEEN TO_DATE('20170101', 'YYYYMMDD') AND TO_DATE('20170301', 'YYYYMMDD')

    --mysql
    SELECT * FROM person WHERE birthdate BETWEEN STR_TO_DATE('20170101', '%Y%m%d') AND STR_TO_DATE('20170301', '%Y%m%d')

    --SQLS, ugh; magic numbers
    SELECT * FROM person WHERE birthdate BETWEEN CONVERT(datetime, '20170101', 112) AND CONVERT(datetime, '20170301', 112)

그렇게하는 것에 대한 나의 기술적 타당성은 날짜 형식에 대해 명시 적이며 소수의 소스 매개 변수가 확실히 대상 열의 데이터 유형이되도록하는 것입니다. 이렇게하면 데이터베이스가 암시 적 변환 (첫 번째 예의 1 월 3 일 / 1 일 3 월 인수)이 잘못 될 가능성을 방지하고 db가 테이블의 백만 날짜 값을 문자열로 변환하지 못하도록합니다 (일부 서버 별 날짜 사용) 비교를 수행하기 위해 sql 내의 문자열 매개 변수의 날짜 형식과 일치하지 않을 수도있는 형식)

그렇게하는 것에 대한 나의 사회적 / 학술적 정당성은 SO가 학습 사이트라는 것입니다. 그것에 관한 사람들은 암묵적으로 또는 명시 적으로 지식을 습득합니다. 이 질문에 대한 답변으로 초보자를 때리는 방법 :

SELECT * FROM person WHERE birthdate BETWEEN '2017-01-01' AND '2017-03-01'

그들이 바람직한 형식으로 날짜를 조정하여 이것이 합리적이라고 생각하게 만들 수 있습니다.

SELECT * FROM person WHERE birthdate BETWEEN '01/01/2017' AND '01/03/2017'

그들이 날짜를 변환하려는 명백한 시도를 적어도 보았을 경우, 이상한 날짜 형식으로 시작하고 영원한 버그가 발생하기 전에 죽일 수 있습니다. 결국, 나는 (I) 사람들이 SQL 주입 습관에 빠지지 않도록 시도하고 설득하려고합니다 (그리고 @pBirthdate프런트 엔드에 날짜 시간 유형이있을 때 쿼리를 매개 변수화 한 다음 문자열 인 드라이버에게 선언하는 사람은 누구 입니까?)

추천을 한 후의 상황으로 돌아 가기 : "일반적으로"다른 사람이하는 일 ","항상 나에게 도움이된다 ","일부 매뉴얼 또는 참조 문서 표시 "와 같이"명시 적으로, x 사용 "추천으로 푸시 백을받습니다. 그것은 "명시 적이어야한다"또는 "무엇입니까?"

나는 이들 중 일부에 응답 WHERE age = '99'하여 연령을 문자열로 전달하여 int 열을 검색할지 여부를 물었습니다 . "어리석게도, 우리는 int을 검색 할 때 '를 넣을 필요가 없다"는 응답이 있기 때문에 어딘가에 다른 데이터 유형에 대한 인식이 있지만 int를 검색하는 논리적 인 도약과는 관련이 없습니다. 문자열을 전달하여 열 (명확하게 어리 석음)과 문자열을 전달하여 날짜 열을 검색하는 것 (겉보기에 합리적인)

따라서 SQL에서 우리는 숫자 (구분 기호없이 숫자 사용), 문자열 문자열 (아포스트로피 구분 기호 사이에 사용)로 쓰는 방법이 있습니다. 왜 날짜에 대한 구분자가 없는가? 대부분의 DB에서 그러한 기본 데이터 유형입니까? 이 모든 것이 자바 스크립트가 /문자의 양쪽 을 넣어 정규식을 지정할 수있는 것과 같은 방식으로 날짜를 쓰는 방법만으로도 해결할 수 있습니까? /Hello\s+world/. 데이트 할 것이없는 이유는 무엇입니까?

실제로, 내 지식으로는 (만) Microsoft Access에는 실제로 "이 구분 기호 사이에 날짜가 기록되었습니다"를 나타내는 기호가 있으므로 우리는 좋은 지름길을 얻을 수 WHERE datecolumn = #somedate#있지만 날짜 표시는 여전히 mm / di vs dd와 같은 문제를 일으킬 수 있습니다. / mm, MS는 항상 VB 군중이 좋은 생각이라고 생각했던 것들로 빠르고 느슨하게 연주했기 때문에


요점으로 돌아가서 :이 매체를 사용하여 명시 적으로 여러 가지 다른 데이터 유형을 문자열로 전달하도록하는 것이 현명하다고 주장합니다.

유효한 어설 션입니까?

이 성전을 계속해야합니까? 문자열로 타이핑하는 것이 현대적인 것이 아니라는 것이 타당합니까? 또는 쿼리를 밀어 넣을 때 모든 RDBMS (고대 버전 포함) WHERE datecolumn = 'string value'가 문자열을 날짜로 정확하게 변환하고 테이블 데이터를 변환하거나 인덱스 사용을 잃지 않고 검색을 수행합니까? 나는 적어도 Oracle 9의 개인적인 경험으로는 아니오라고 생각합니다. 문자열이 항상 ISO 표준 형식으로 작성되고 열이 날짜 풍미 인 경우 도망가는 시나리오가있을 수도 있습니다. 문자열 매개 변수는 항상 내재적으로 올바르게 변환됩니다. 이것이 제대로됩니까?

가치있는 일입니까?

많은 사람들이 그것을 얻지 못하거나 신경 쓰지 않거나 그들의 int는 int이지만 날짜는 문자열이라는 점에서 위선을 보입니다. 뭐, 당신의 요점에 동의합니다


나는 WHERE datecolumn = 1912, 2012, 2001, 1901, 12 또는 1 년을 요청할 수있는 01/02/12 '`에 문제가있는 사람을 보았습니다 . 또한 데이터베이스 세계 외부의 문제이기도합니다. "09"int 로 변환 하는 것이 충돌을 일으키는 이유를 이해할 수없는 프로그래머의 수 는 군단이고, 9는 유효한 8 진수가 아니며 앞의 0은 많은 시스템에서 문자열을 8 진수로 만듭니다
Steve Barnes

2
WHERE age = '0x0F'데이터베이스가 15 살짜리를 검색 할 수있는 올바른 방법 인지 묻기 위해 예제를 확장하려고 생각 했습니다.
Caius Jard

1
여기서는 주제가 아닌 질문을 삭제했습니다. 리소스 요청은하지 않습니다. 이 때문에 2 개의 찬성표 중 하나가 주어졌습니다. 그렇지 않으면, 이것이 너무 넓은 범위에 속할 수도 있지만 이것이 유효한 질문이라고 생각합니다. 주제를 벗어난 질문을 제거하면 사물을 조금 좁히는 데 도움이되기를 바랍니다.
Thomas Owens

TL; DR이지만 프로덕션 시스템에서는 이와 같은 날짜가 거의 항상 매개 변수에있을 것으로 예상합니다. 날짜를 쿼리로 하드 코딩하는 것은 암시 적 변환 사용 여부보다 더 큰 문제입니다. 일부 버림 쿼리를 작성하는 경우 작동하거나 작동하지 않습니다. 어쨌든 (기본 날짜 형식을 기억할 수 없기 때문에)이 작업을 수행하지는 않지만 중요하지는 않습니다.
JimmyJames

1
인생은 당신의 전투를 선택하는 것입니다. 내 생각에, 이것은 싸울 가치가 없다 ...
Robbie Dee

답변:


7

당신은 썼습니다 :

1 월 1 일부터 3 월 1 일 또는 3 월 1 일의 매개 변수입니다.

실제로 잠재적 인 오류의 원인입니다. 이것을 독자에게 지적하면 다른 독자들에게 도움이 될 수 있으므로, 이것은 유효한 관심사입니다. 그러나 건설 적이기 위해서는

  • ANSI SQL을 참조하고 해당 표준의 DATE 또는 DATETIME 리터럴을 사용하십시오.

  • 특정 DBMS의 일반적이고 명확한 날짜 / 시간 형식을 사용하십시오 (그리고 사용되는 SQL 언어를 언급하십시오)

불행히도, 모든 DBMS가 ANSI SQL 날짜 리터럴을 정확히 유사한 방식으로 지원하지는 않습니다 (아직 지원하는 경우). 이는 일반적으로 두 번째 접근 방식의 변형으로 이어질 것입니다. "표준"이 다른 DB 벤더에 의해 엄격하게 구현되지 않았다는 사실은 아마도 여기서 문제의 일부일 것입니다.

또한 많은 실제 시스템의 경우 클라이언트 응용 프로그램이 지역화되어 있어도 항상 같은 방식으로 구성되는 서버가 하나뿐이기 때문에 사람들은 실제로 데이터베이스 서버의 특정 고정 로캘에 의존 할 수 있습니다. 따라서 '01 / 03 / 2017 '은 종종 특정 시스템에서 사용되는 SQL에 대해 고정 형식'dd / mm / yyyy '또는'mm / dd / yyyy '를 갖는 것으로 가정 할 수 있습니다. 누군가가 "항상 나를 위해 일한다"고 말하면 실제로 그의 환경에 대한 합리적인 대답 일 입니다. 이 경우이 주제에 대해 논의 할 가치가 줄어 듭니다.

"성능 이유"에 대한 이야기 ​​: 측정 가능한 성능 문제가없는 한, "잠재적 성능 문제"와 논쟁하기에는 미신적입니다. 데이터베이스가 백만 개의 문자열을 날짜로 변환하거나 시간 차이가 1/1000 초일 때 중요하지 않은 경우 실제 병목 현상은 네트워크가 쿼리를 10 초 동안 지속시키는 네트워크입니다. 따라서 성능 고려 사항을 명시 적으로 요청하는 한 이러한 문제를 해결하는 것이 좋습니다.

이 성전을 계속해야합니까?

나는 당신에게 비밀을 말합니다 : 나는 종교적인 전쟁을 싫어합니다. 그들은 유용한 것을 이끌어 내지 않습니다. 따라서 SQL의 모호한 날짜 / 시간 스펙이 문제점을 야기 할 수있는 경우 문제점을 언급하되 현재 상황에서 실제로 이점을 얻지 못하는 경우 사람들을 더 강하게 만들려고하지 마십시오.


그러나 American vs Sensible 날짜 형식의 모호성에 대해서는 그리 큰 의문이 아닙니다. SQL 문에서 날짜를 문자열로 전달하는 것이 현명한 지, 날짜로의 암시 적 변환에 의존하는지 여부에 관한 것입니다. 데이터베이스가 백만 행에 대해 백만 개의 날짜-> str 변환을 수행해야한다는 문제는 하나의 성능 측면이며, 하나의 쿼리에 대해 1/1000 초만 소요될 수 있지만 이제는 동시에 동시 상황에서이를 상상하십시오. 사용자. 더 큰 성능 문제는 데이터 변환이 인덱스를 더 이상 사용할 수없고 실제로 심각 할 수 있다는 것을 의미 합니다.
Caius Jard

@ CaiusJard : 내 대답은 의미가 있습니다 : 때로는 합리적이며 때로는 상황에 따라 다릅니다. 그리고 솔직히, 나는 여기서 "... 상상해 ..."를 거부합니다 . 성능과 관련하여 가상의 사례를 논의하는 것은 유용하지 않습니다. 측정 가능한 성능 문제가있는 경우 사전이 아닌 최적화하고 때로는 미세 최적화해야합니다.
Doc Brown

가설로 보는 것이 흥미 롭습니다. (:가 검색되기 전에 전체 열 데이터가 변형되는 경우 인덱스가 일을하지 않는 문서화 이유), 및 명시 적 지침이 일어날 수 없습니다 나는 발생하는 버그와 성능 합병증에 대한 명확한 기회로 암시 적 행동에 의존 참조
카이 우스를 Jard

@CaiusJard : 단어로 연주하지 마십시오. "가설 적"이라는 말은 "아마도"를 의미하지 않습니다. 나는 어떤 상황이 발생했는지를 측정 할 수있는 "실제 기존 상황"이 아니라 상상 된 시나리오에 대해이 용어를 사용했습니다.
Doc Brown

1
@CaiusJard : 다른 업계 전문가에게 깊은 인상을 주려면 "성능 최적화"가 "보안 최적화"와 매우 다른 이유를 정확히 알아야합니다. 이것이 바로 내 요점입니다. 성능 문제가 발생한 후에 처리 할 수있는 경우는 거의 없습니다. 너무 늦었 어 보안 문제는 발생하기 전에 철저히 피해야합니다. 사과와 오렌지를 비교하지 마십시오. 십자군을 좋아한다면 보안 주장이 훨씬 더 적합합니다. ;-)
Doc Brown

5

십자군이 문제를 해결하지 못합니다.

두 가지 별도의 문제가 있습니다.

  • SQL에서 암시 적 유형 변환

  • 05/06/07과 같은 모호한 날짜 형식

나는 십자군과 함께 어디에서 왔는지 알지만 명시 적 변환이 실제로 문제를 해결한다고 생각하지 않습니다.

  • 비교에서 유형이 일치하지 않는 경우에도 암시 적 변환이 계속 발생합니다. 문자열이 날짜와 비교되면 SQL은 문자열을 먼저 날짜로 변환하려고 시도합니다. 따라서 날짜 유형 열을 명시 적으로 변환 된 날짜 값과 비교하는 것은 문자열 형식의 날짜를 비교하는 것과 정확히 동일합니다. 내가 볼 수있는 유일한 차이점은 날짜 값을 실제로 날짜가 아닌 문자열을 포함하는 열과 비교하는 경우입니다. 그러나 이것은 어떤 경우에도 오류가됩니다.

  • 명시 적 변환을 사용해도 ISO가 아닌 날짜 형식의 모호성이 해결되지는 않습니다.

내가 보는 유일한 솔루션 :

  • 문자열 유형 열을 문자열이 아닌 값과 비교하지 마십시오.
  • ISO 형식 날짜 형식 만 사용하십시오.

물론 날짜를 문자열 유형 열에 저장하지 마십시오. 그러나 날짜 리터럴을 명시 적으로 변환해도이를 방지 할 수는 없습니다.

아마도 암묵적인 변환은 SQL에서 실수 였지만 언어가 어떻게 설계되어 있는지에 따라 명시적인 변환의 이점을 보지 못합니다. 어쨌든 암시 적 변환을 피하지 않으며 코드를 읽고 쓰기가 더 어려워집니다.


진실. 아마도이 관점에서 지적해야 할 가장 중요한 것은 날짜 열 피연산자와 값 피연산자가 동일한 데이터 유형 (문자열, 날짜 등)을 갖도록하는 것입니다. 내가 특별히 단지 내가 질문이 추천해야합니까 알고 테이블 열이 DATETIME과 예제 대답은 암시 적 변환 된 문자열 피연산자를 사용하고 있습니다 ..
카이 우스 JARD

이 답변에 나와 맞지 않는 것이 있습니다. 당신은 몇 가지 흥미로운 점을 제시하지만 결론은 이상 주의적이라고 생각합니다. 디자인 관점에서 볼 때 ISO가 아닌 날짜 형식은 사람의 눈에는 모호하지만 명시적인 변환을 사용하는 경우 구문 적 으로는 파서가 모호 하지 않습니다 . 마찬가지로, 날짜를 포함하는 많은 ETL 프로세스를 요구하려고하는 일부 데이터베이스의 날짜 형식 문자열 (파일 가져 오기의 형태로) 비교. 문자열 대 날짜 비교를 제거하려고 시도하는 것은 비현실적입니다.
DanK

@ DanK : ETL은 다른 문제입니다. CSV 파일이나 다른 데이터에서 데이터를 읽는 경우 분명히 데이터를 문자열로 처리하고 유형 값으로 명시 적으로 구문 분석해야합니다. 그러나 OP가 설명하는 시나리오는 아닙니다.
JacquesB

그것은 내가 설명하고있는 요점 일 수 있습니다. 구문 분석 할 때 형식을 명시 적으로 선언 해야하는 csv에 저장된 일련의 숫자에 대해서는 특별한 것이 없으며 전문가가 명시 적으로 노력하지 않는 초보자가 SO에서 일부 답변을 읽는 경우 내가 만드는 인수와 관련이 있습니다. 날짜 형식을 선언하여 초보자가 걱정할 필요가 없다고 생각하게합니다 (또는 db가 항상 올바르게 구문 분석 할 것임)
Caius Jard

@ CaiusJard : 나는 이것이 매우 다른 시나리오라고 생각합니다. 일반적인 시나리오에서 SQL에 대해 이야기 할 때 열에는 적절한 유형이 있다고 가정합니다. 즉 정수 열은 정수 유형, 날짜 열은 데이터 유형 등입니다. 테이블에 올바른 유형이없는 경우 (예 : 날짜를 문자열로 저장) 문제가 발생하여 쿼리에서 날짜 리터럴을 명시 적으로 변환 하면 저장하지 않습니다 .
JacquesB

3

무엇보다도 중요한 점이 있습니다. 날짜는 문자열에 넣지 않아야합니다. 데이터베이스 엔진은 복잡한 쿼리로, 임의의 쿼리가 주어지면 정확히 어떤 일이 일어날 지 100 % 확신 할 수 없습니다. 날짜로 변환하면 모호하지 않고 성능이 향상 될 수 있습니다.

그러나

대부분의 사람들이 해결해야 할 추가 노력의 가치는 없습니다. 쿼리에서 날짜 리터럴을 사용하기 쉬운 경우 위치를 쉽게 방어 할 수 있습니다. 그러나 그렇지 않습니다. 나는 주로 SQL Server를 사용하므로 날짜를 변환하는 혼란은 일어나지 않는다는 것을 기억하려고합니다.

대부분의 사람들에게는 성능 향상이 무시할만한 수준입니다. "그렇습니다. 보스 맨 씨, 저는이 간단한 버그를 고치는데 10 분을 더 썼습니다. (구문이 ... 특별하기 때문에 날짜를 변환하는 방법을 구글에 보내야했습니다.)하지만 0.00001 초를 더 절약했습니다. 거의 실행되지 않는 검색어입니다. " 그것은 내가 일했던 대부분의 장소를 비행하지 않을 것입니다.

그러나 그것은 당신이 말하는 날짜 형식의 모호성을 제거합니다. 다시 말하지만, 많은 응용 프로그램 (회사 내부 응용 프로그램, 지방 정부 물건 등)의 경우 실제로 걱정하지 않습니다. 그리고 UI / 비즈니스 계층 문제가되거나 우려되는 응용 프로그램 (대규모, 국제 또는 엔터프라이즈 응용 프로그램)의 경우 이미 이미 잘 알고있는 DBA 팀이 이미있는 회사입니다. TL / DR : 국제화가 우려되는 경우 누군가 이미 생각하고 있고 이미 제안한대로 (또는 문제를 완화 한 경우) 수행했습니다.

그래서 지금 무엇?

기분이 너무 좋다면 계속해서 좋은 싸움을하십시오. 그러나 대부분의 사람들이 이것이 걱정할만큼 중요하다고 느끼지 않는다면 놀라지 마십시오. 중요한 상황이 있다고해서 그것이 모든 사람의 상황이라는 것을 의미하지는 않습니다. 따라서 기술적으로 정확하고 더 낫지 만 실제로는 관련이없는 것을 원한다면 당황하지 마십시오.


1

이 매체를 사용하여 명시 적으로 표현하는 것이 현명하다고 주장합니다.이 매체는 수많은 다른 데이터 유형을 문자열로 전달해야합니다.

"날짜"가 "in" 문자열 주위로 전달되고 있다고 가정하면 예; 나는 당신이 이것을 할 권리에 동의 합니다.

"01/04/07" 언제 입니까?
* 1 월 4 일?
* 4 월 1 일?
* [2001 년 4 월 7 일?

"컴퓨터"가 해석하는 방법에 따라 이들 중 일부 또는 전부 가 정확할 있습니다.

리터럴을 사용하여 동적 SQL 을 작성 해야하는 경우 날짜 형식을 잘 정의하고 가급적 기계 독립적이어야합니다 (Windows 서비스에서 날짜 기반 처리가 잘못 된 Windows Server에서 이상한 형식이 발생했습니다) 운영자가 다른 날짜 형식 환경 설정으로 콘솔에 로그온했기 때문입니다!). 개인적으로 나는 독점적으로 "yyyy-mm-dd"형식을 사용합니다.

그러나 ...

가장 좋은 솔루션은 데이터 형식을 강제 매개 변수화 쿼리 변환 할 사용하는 것입니다 전에 SQL 참여 도착 -에 "날짜"값을 얻는 에 초기 파라미터 힘 유형 변환 (순수 코딩 문제를 만들기가 아닌 SQL의 하나) .


나는 WHERE datecolumn = @dateParameter프론트 엔드 코드 를 수행 한 다음 @dateParametervarchar 유형 의 DB 드라이버에 알리고 고착 시킴으로써 매개 변수가있는 쿼리로 동일한 문제를 해결할 수 있다고 동의 "01/04/07"합니다. 내 질문에 대한 원래의 영감은 매개 변수가있는 쿼리에 저를 미쳤다고 말한 사람이 같은 호흡에서 다음과 같은 한 줄의 SO 답변을 줄 것이라고 의심 WHERE datecol = 'some string that looks like a date'한다는 것입니다. 그것은 문제를 피하기 위해 힌트 / 매개 변수입니다.)
Caius Jard
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.