2014-07-25 8 views
1

저는 Text :: CSV를 사용하여 CSV 파일을 읽고 필드를 구문 분석 한 다음 DBI를 통해 SQL Server에 레코드를 씁니다. 모든 필드는 조작해야하는 날짜 필드를 제외하면 황금색입니다.Perl - DBI 문자열이 잘못 큰 따옴표로 묶입니다.

CSV의 날짜 필드 형식은 'Fri Dec 20 14:56:54 2013'과 같습니다. 물론 SQLServer는 그 형식을 좋아하지 않습니다. 인체 공학적,이 블록을 사용하고 스크립트에서 다음 CSV에서 필드는 단어 '없음'을 포함하는 경우

if ($i == 12 || $i == 13 || $i == 22 || $i == 23 || $i == 24 || $i == 25) 
    { 
     if (defined $fields[$i]) 
     { 
      $dummy = UnixDate($fields[$i],'%m/%d/%Y %H:%M:%S'); 
      $fields[$i] = $dummy; 
     } 
    } 

(정의 된 검사, 그럼 내가 그래서 그 요소 상 미확정하고 있어요 때문에를 DB를 삽입 할 때 필드는 NULL이 될 것이다이 샘플 열에서, 요소 (24)를 제외한 컬럼/모든 필드 및 25 '없음'없음)

DBI 추적 켜기 날 보여준다..

<- bind_param(19, '1')= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(20, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(21, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(22, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(23, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(24, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(25, "12/20/2013 14:56:54")= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(26, "12/20/2013 14:55:37")= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(27, 'Unknown')= (1) [1 items] at upload_merged_host.pl line 71 

CSV의 다른 필드/열이 올바르게 바인딩되어 있음을 볼 수 있습니다 (위의 '1'및 '알 수 없음'). 지금 조작 한 날짜 필드/열에는 큰 따옴표가 붙어있어서 SQL은 만족스럽지 않습니다. 내가 날짜 필드를 조작하지 않으면 더 명확성을 위해

, 그것은 올바르게 따옴표가없는,하지만 SQLServer에 허용되는 형식으로 더 이상 :

<- bind_param(19, '1')= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(20, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(21, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(22, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(23, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(24, undef)= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(25, 'Fri Dec 20 14:56:54 2013')= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(26, 'Fri Dec 20 14:55:37 2013')= (1) [1 items] at upload_merged_host.pl line 71 
<- bind_param(27, 'Unknown')= (1) [1 items] at upload_merged_host.pl line 71 

는 포인터/제안 싶어요!

업데이트 : @ Vinbot의 의견은 저에게 뭔가를 시도했습니다. UnixDate에서 날짜 문자열을 조작하는 대신, 시작 부분에서 요일을 잘라내는 것이 어떻습니까? 이제 다음과 같이 보입니다.

$ fields [$ i] = substr ($ fields [$ i], 4);

그리고 내가 무엇을 추적 에보고하고있어 지금은 갈 수 있어야한다 :

... 
<- bind_param(25, 'Dec 20 15:33:42 2013')= (1) [1 items] at upload_merged_host.pl line 93 
... 

하지만 난 여전히 이전과 같은, 주조 오류를 받고 있어요. 동일한 형식을 SQL에 직접 사용할 때 문제가 없습니다 (예 : SQL Server 관리 스튜디오를 통해).

INSERT INTO <schema>.dbo.host(hostname,interface_ipaddress,interface_name,host_modified_date) VALUES ('some_host','10.1.1.1','Local Area Connection','Dec 20 15:33:42 2013') 

잘 작동합니다.

갱신 2
(적어도, 기능의 I 여전히 변화를 최적화해야하지만) 나는 수 사용은 다른 날짜 조작 루틴이고 문제는 이제 해결됩니다.

해결 방법은 DateTime 및 DateTime :: Format :: DBI를 사용하는 것이 었습니다. 현재로서는 CSV에서 DateTime-> new()로 전달한 다음 DateTime :: Format :: DBI-> format_datetime()에 해당 값을 전달할 때 날짜 문자열을 수동으로 조작해야합니다.

잠을 자고 싶을 때 방금 내가 한 무력의 일부를 잘라낼 수 있기를 바랍니다! :)

+0

내 스파이 지언은 서식에 슬래시가 필요하다는 사실과 관련이 있다고합니다. 당신이 그들을 제거하면, 그것을 단일 인용합니까? – Vinbot

+0

바인딩하지 않고 적절한 형식을 지정하면 제대로 작동합니다. – Hambone

+0

매개 변수가 전달하는 값과 정렬되지 않을 수 있습니까? 그들 중 36 명과 함께, 하나는 쉽게 빠져 나올 것이라고 생각할 것입니다. bind_param은 실제로 Perl 관용구처럼 0이 아니라 1에서 시작한다고 생각합니다. 날짜 필드만으로 스 니펫을 다시 시도해 볼 수 있습니까? – Hambone

답변

1

나는 당신이 당신의 문제를 잘못 진단했을 수도 있고 당신이 우리에게 완전한 정보를주지 않았다고 생각한다.a) MS SQL Server에 연결하기 위해 어떤 DBD를 사용하고 있는지, b) 날짜에 대한 열 유형 및 c) 얻고있는 정확한 오류 메시지를 알고 있으면 좋았을 것입니다.

MS SQL Server와 대화하기 위해 DBD :: ODBC를 사용한다고 가정하겠습니다. 그러나 그 중 많은 부분은 중요하지 않으며 열은 datetime입니다.

첫 번째 것은 bind_param에 대한 추적 출력이 모든 매개 변수를 따옴표로 묶어서 귀하의 datetime이 신비하게 인용되고 있다고 생각하지 않는다는 것입니다. 두 번째는 ODBC가 특히 datetime을 사용한다고 생각하지 않는다는 것입니다. "숫자 값이 범위를 벗어났습니다 : 날짜/시간 문자열에 유효하지 않은 문자"또는 "캐스트에 대해 유효하지 않은 값"과 같은 오류가 있었다면 datetime이 잘못된 형식임을 입증 할 것입니다.

ODBC에서 datetime/timestamp를 입력하는 정확한 방법은 {ts 'yyyy-mm-dd hh : mm : ss'}이며 드라이버는 올바른 것을 데이터베이스에 보내야합니다. 성공적으로 바로 드라이버가 문자열 날짜를 통과하지 않는 데이터베이스 엔진이 아닌 드라이버 배후의 보장되지 않는 SQL 서버 관리 스튜디오로 날짜를 입력 염두에

use 5.016; 
use strict; 
use warnings; 
use DBI; 

my $h=DBI->connect("dbi:ODBC:abc","xx","yy", {RaiseError => 1, PrintError => 0}); 
eval { 
    $h->do(q/drop table mje/); 
}; 
$h->do(q/create table mje (a varchar(50), b datetime)/); 

my $s = $h->prepare(q/insert into mje values(?,?)/); 
$s->bind_param(1, 'fred'); 
$s->bind_param(2, "{ts '2013-12-20 14:55:37'}"); 
$s->execute; 
# or $s->execute("fred", "{ts '2013-12-20 14:55:37'}"); 

곰, 그것은 무언가로 그것을 구문 분석 else (물론 datetime이 SQL 자체에없는 경우). 또한 세션은 다른 datetime 입력 형식을 가질 수 있습니다.

+0

당신이 그 지점을 놓친 것이 두렵습니다. datetime 문자열의 형식은 올바르지 만 sql-server가 큰 따옴표로 묶인 문자열을 받으면 작은 따옴표로 묶은 문자열과 다르게 해석합니다. 그러나 ts {}는 bind_param에 전달 될 때 double-quoted 될 수 있기 때문에 메서드가 작동하고 어젯밤에 생각해 낸 솔루션보다 짧습니다 (TS를 전달할 때부터 추가해야 함). {} 변수를 만들려면 리 포맷 된 날짜 문자열이 포함 된 변수 이름을 이스케이프 처리 된 작은 따옴표로 묶어야했습니다. – Chris

+0

글쎄, 나는 정보가 충분하지 않은 질문을 토대로 최선을 다했으며, 당신이 사용했던 것을 제공하고, 무엇을했는지, 그리고 오류 메시지와 함께 작동하지 않았는지를 잘못 제시했다고 생각했던 것을 기반으로 제시했다. 더블 쿼트와 싱글 쿼트를 다르게 처리하는 SQL Server의 경우에는 이중 쿼트는 식별자 용이며 작은 따옴표는 문자열 용입니다. 그러나 너무 많은 정보가 빠져서 당신이 의미하는 것을 알기가 어렵습니다. – bohica