2009-10-18 3 views
3

Perl과 DBI (SQLite yay!)에 작은 스 니펫을 작성했습니다.Perl의 DBI를 사용하여 SQL 쿼리에서 테이블 이름을 가져올 수 있습니까?

쿼리가 실행되는 테이블 이름과 동일한 파일 이름의 텍스트 파일에 특정 쿼리를 기록하고 싶습니다 . 가는 대신 물건, 내가 효과적으로 원하는 것은

dumpResultsToFile (<<" END_SQL"); 
    SELECT TADA.fileName, TADA.labelName 
    FROM TADA 
    END_SQL 

:

여기
sub dumpResultsToFile { 
    my ($query) = @_; 

    # Prepare and execute the query 
    my $sth = $dbh->prepare($query); 
    $sth->execute(); 

    # Open the output file 
    open FILE, ">results.txt" or die "Can't open results output file: $!"; 

    # Dump the formatted results to the file 
    $sth->dump_results(80, "\n", ", ", \*FILE); 

    # Close the output file 
    close FILE or die "Error closing result file: $!\n"; 
} 

내가이 전화를 할 수있는 방법입니다 : 여기

내가 텍스트 파일로 결과를 덤프하기 위해 사용하는 코드입니다 "results.txt"(위에 하드 코딩 된), 이제 "TADA.txt"로 이동합니다.

이는 테이블 사이에 "HAI"및 "LOL"다음 결과 집합을 "HAI.LOL.txt"

작성해야 가입 나는 DBI의 마법을 사용하는 경우에도 가능 말하고 무엇인가 있었다면 ?

는 차라리 테이블에 대한 SQL 쿼리를 구문 분석없이 할 것입니다,하지만 SQL 쿼리 소스 테이블 이름을 잡기 위해 널리 사용되는 및 디버깅 기능이있는 경우, 그 역시 나를 위해 작동합니다.

내가 원하는 것은 파일명이 인 것일뿐 어떤 결과가 나오는지에 대한 힌트가 있습니다. 출력 결과가 아닙니다. 테이블 이름을 기반으로하는 세그레게이션은 지금 좋은 방법입니다.

답변

4

아마도 그렇지 않습니다. SQL 생성 코드가 잘못된 접근 방식을 취합니다. 당신은 당신의 프로그램에서 너무 많은 정보를 숨기고 있습니다. 어떤 시점에서 프로그램은 선택할 테이블을 알고 있습니다. 그 정보를 버리고 불투명 한 SQL 명령 안에 포함시키지 말고 그대로 두어야합니다. 그런 다음 로거 기능은 로그 데이터가 어디로 가야 하는지를 추측 할 필요가 없습니다. 그것 알고.

일부 코드의 경우 더 명확합니다. 귀하의 코드는 다음과 같습니다 :

sub make_query { 
    my ($table, $columns, $conditions) = @_; 
    return "SELECT $columns FROM $table WHERE $conditions"; 
} 

sub run_query { 
    my ($query) = @_; 
    $dbh->prepare($query); 
    ... 
} 

run_query(make_query('foo', '*', '1=1')); 

이렇게하면 원하는 작업을 수행 할 수 없습니다. 그래서 당신은 같은 것을 할 수 프로그램 구조해야합니다

sub make_query { 
    my ($table, $columns, $conditions) = @_; 
    return +{ 
     query => "SELECT $columns FROM $table WHERE $conditions", 
     table => $table, 
    } # an object might not be a bad idea 
} 

sub run_query { 
    my ($query) = @_; 

    $dbh->prepare($query->{query}); 
    log_to_file($query->{table}.'.log', ...); 

    ... 
} 

run_query(make_query('foo', '*', '1=1')); 

API를하는 것은 동일하지만, 지금 당신은 당신이 에게 당신이 원하는 방식으로 로그인하는 데 필요한 정보가 있습니다.

또한 동적 SQL 생성의 경우 SQL::Abstract을 고려하십시오. 위 코드 은 예제 일뿐입니다.

편집 : 좋아, 당신은 SQLite를 사용하고 있다고합니다. TableLock은 당신이보고 싶은 것이 무엇처럼

sqlite> explain select * from test; 
0|Trace|0|0|0|explain select * from test;|00| 
1|Goto|0|11|0||00| 
2|SetNumColumns|0|2|0||00| 
3|OpenRead|0|2|0||00| 
4|Rewind|0|9|0||00| 
5|Column|0|0|1||00| 
6|Column|0|1|2||00| 
7|ResultRow|1|2|0||00| 
8|Next|0|5|0||00| 
9|Close|0|0|0||00| 
10|Halt|0|0|0||00| 
11|Transaction|0|0|0||00| 
12|VerifyCookie|0|1|0||00| 
13|TableLock|0|2|0|test|00| 
14|Goto|0|2|0||00| 

가 보이는 : 그것은 당신의 출력을 구문 분석 할 수있는 명령 을 EXPLAIN 있습니다. YMMV,이 은 좋지 않은 아이디어입니다.

+0

SQL :: Abstract에 대한 제안이 매우 좋습니다! – PoorLuzer

+0

.. 내가 묻는 것은 : DBI 문 핸들에서 소스 테이블 이름을 가져올 방법이없는 것입니까? (준비 등으로 반환 된 핸들) – PoorLuzer

+0

@ PoorLuzer : 정보를 얻는 방법이 있을지 몰라도, 누군가가 추천 할만한 것은 아닙니다. 'prepare' 문은 아마도 데이터베이스 드라이버의 일부인 C 루틴을 호출하고 쿼리를 해당 데이터베이스의 내부 형식으로 변환 할 것입니다. 어떻게 든 정보를 다시 가져 오는 것은 가능해야하지만, 다른 선택의 여지가 없다면 갈 방법이 아닙니다 (예 : 다른 곳에서 제공되는'prepare'd 쿼리). –

4

일반적으로 SQL에서는 이론적 인 이유 (결과 집합은 계산 열로 만 구성 될 수 있음)와 실용적인 결과 집합 (결과 집합에는 테이블 이름 - 열 이름 만 포함 할 수 없음) 때문에 결과 집합에서 테이블 이름을 안정적으로 추론 할 수 없습니다. 데이터에 있음).

그래서 사용 된 테이블을 확인하는 유일한 방법은 원본 쿼리와 함께 저장하거나 추론하는 것입니다.

3

SQL::Statement의 구문 분석 기능에 대해 좋은 말을들은 적이 있지만 지금까지는 사용하지 않았습니다.

use SQL::Statement; 
use strict; 
use warnings; 

my $sql = <<" END_SQL"; 
    SELECT TADA.fileName, TADA.labelName 
    FROM TADA 
    END_SQL 
my $parser = SQL::Parser->new(); 
$parser->{RaiseError} = 1; 
$parser->{PrintError} = 0; 
my $stmt = eval { SQL::Statement->new($sql, $parser) } 
    or die "parse error: [email protected]"; 
print join',',map{$_->name}$stmt->tables; 
관련 문제