簡體   English   中英

如何使用面向對象的Perl組裝SQL?

[英]How can I assemble SQL with object-oriented Perl?

我目前負責一個似乎與數據庫非常親密的過程。 我的程序/腳本/框架的目標是從不同的數據源中實現統一。 使用依賴注入的形式,我的進程在很高的水平上工作正常。 每個數據源類型的實現都隱藏在最高級別的業務抽象中。 大。 我的問題是兩個。

1)我有一個很長的段落(這是困擾我的長度),它在Perl空間中組裝了一個如何將這些不同數據源轉換為一個同類結束格式的SQL語句。 所以SQL字符串總是取決於我正在使用的數據類型。 WHERE子句依賴,FROM子句依賴,INSERT子句依賴,它全部依賴。 這是高度依賴性讓我感到困惑。 如何以面向對象的方式對此過程進行建模? MagicObject-> buildSQL? 這基本上就是我現在所擁有的,但感覺代碼的所有部分都知道太多,因此它的長度。

2)如果我有一個能做某事的函數(構建SQL?),我是否將整個業務對象傳入,然后在最后一分鍾對它們進行字符串化? 或者我是否盡早將它們串聯起來,只讓我的函數處理它需要的東西,而不是渲染對象本身?

編輯 :雖然我不懷疑ORM的重要性,但我不認為我們還處於ORM領域。 想象一下,美國,國家和虛構聯盟的棒球數據都以不同的格式存儲,具有不同的標准化水平。 讀取這些數據源並將它們放在一個統一的規范化池中是我的過程的工作。 我覺得在我的過程之后發生了對這些物體采取行動的ORM空間。 如果你願意,我是一名數據看門人。 由於缺少我創建的統一池,因此基本上沒有業務對象可以采取行動。

編輯^ 2 :引起我的注意,也許我沒有詳細描述問題空間。 這是一個例子。

想象一下,你必須建立一個美國所有罪犯的主數據庫。 貴公司的服務是銷售一種產品,該產品位於頂部並以干凈,統一的格式提供對這些數據的訪問。

這些數據由50個州公開提供,但格式完全不同。 有些是一個數據文件,沒有標准化。 其他是CSV格式的規范化表格。 有些是Excel文檔。 有些是TSV。 甚至提供了一些在沒有人工干預的情況下不完整的記錄(其他,手動創建的數據源)。

我的項目的目的是為50個州中的每個州制定一個“驅動程序”,並確保該過程的最終產品是一個完美的關系模型中的犯罪分子的主數據庫。 一切都正確鍵入,架構完美,等等。

你想看看Fey 幾個月前我開始在工作中使用它,雖然由於年齡的原因,實施仍然有嚴峻的角落,但它背后的想法是可靠的。 F.ex.,從手冊中略微改編一下查詢:

my $user = $schema->table( 'user' );
my $q = Fey::SQL
    ->new_select
    ->select( $user->columns( 'user_id', 'username' ) )
    ->from( $user );

現在你可以寫一個這樣的函數:

sub restrict_with_group {
    my ( $q, $table, @group_id ) = @_;
    my $group = $schema->table( 'group' )->alias;
    $q
        ->from( $table, $group )
        ->where( $group->column( 'group_id' ), 'IN', @group_id );
}

這將添加從usergroup的內部聯接以及WHERE條件。 瞧,您可以在主程序中編寫以下內容:

restrict_with_group( $q, $user, qw( 1 2 3 ) );

但是這個restrict_with_group函數適用於具有group表外鍵的任何查詢! 要使用它,請傳遞要限制的查詢以及要應用限制的表,以及要將其限制到的組ID。

最后你會說$q->sql( $dbh ) ,你會得到一個SQL字符串,代表你在$q對象中建立的查詢。

因此,Fey基本上為您提供了原生SQL缺失的抽象功能。 您可以從查詢中提取可重用的方面,並將它們打包為單獨的函數。

請不要編寫自己的ORM。 使用類似DBIx :: Class的東西。

您提到的所有這些問題都已解決,並且已在數千個其他應用程序中測試了該實現。 堅持編寫你的應用程序,而不是重新實現庫。 您可能實際上並未在應用程序中使用 DBIC,但您應該查看其實現方法; 特別是它如何逐步構建ResultSet(不是結果集,而是延遲查詢)。

如果你想要一個ORM,但你想從沒有直接字符串操作/連接的位組裝SQL,請看看Fey ,它可能會做你想要的。

更新:亞里士多德Pagaltzis的答案要好得多。 他實際上給出了Fey看起來像以及它如何幫助的例子。

從純粹的編碼角度來看 - 您手上有一長串復雜的代碼。 你不喜歡它。 為什么? 我只能假設那里有一些代碼重復。 否則,有什么不喜歡的? 因此,重構它以消除重復...我知道它聽起來很陳舊,但由於你沒有發布代碼,因此很難更具體。 可能有一個對象具有from,where和insert子句的方法,以便SQL的基礎結構不重復? 我確實不知道該怎么做,但消除重復是關鍵。

除非我誤解,否則這似乎是一個ETL(提取/轉換/加載)應用程序,它沒有想出要將這三個階段分開。

如果輸出模型只是一兩個表,那么你可能也可以使用SQL。 否則,特別是如果你要插入的表之間存在關系,那么一個體面的ORM應該簡化一些事情。

采用50個國家的想法,你無法真正擺脫50個“提取”過程,希望有一個共享例程庫。 我一次攻擊一個輸入源的問題,重構,因為我添加了新的,但小心地封裝了可變部分,以便我知道當供應商更改其格式時需要做出哪些更改。

“變換”部分不應過於繁瑣:只需拿走你得到的東西並准備輸出即可。

我想你在運行時以編程方式描述動態SQL構建請求。 這是對象關系映射器的常見功能,例如LINQ to SQL和LLBLGenPro,僅舉幾例。 建立一個不是一項小任務。

通常,ORM將SQL語言客觀化。 您編寫了一種“SQL文檔對象模型(DOM)”,它允許您通過將它們(例如)表示為“請求”對象來以編程方式構建SQL查詢。 然后,您可以在Request對象上設置屬性,例如Column集合,Table集合和Join集合(這些只是一種方法的示例。)結果將是一個SQL請求字符串,公開為Request對象的屬性。

您還必須使Request對象能夠讀取數據源的模式定義。 您提到您的WHERE子句是類型相關的。 因此,您的SQL匯編程序必須能夠讀取架構並適當地構建子句。

對你的案子來說,這可能有點過頭了。 我認為根本問題是,您是否絕對需要動態SQL查詢,或者是否有一個不太復雜的選項來滿足您的要求?

在我看來,你可能需要考慮解決這個問題的方法。 您當前有多個數據源,您需要將其視為單個數據源。 那么為什么要將它們作為單獨的數據源?

根據數據更新的頻率(或查看性能,訪問頻率),您可以將數據組合到臨時數據源(如SQLite)中。 如果來自每個州的數據都有一個轉換程序,它將從格式A轉換為SQLite表中的通用格式,那么您可以使用您選擇的方法來訪問它。

此方法還允許靈活性,因為您的數據訪問需求可能會發生變化。 例如,如果您被問到這樣一個問題:“每個州都有多少金發司機有超速罰單?”。 SQLite數據庫可以使用單個命令執行此操作,而其他解決方案可能需要返回一組數據,然后需要對其進行解析,分組和設置以進行輸出。

如果你不想處理ORM,我經常有這樣的代碼:

my (@columns,@tables,@wheres,@order_bys,@values);

... # Add value to those variables as needed, using push.
... # use ? for variables to be quoted

# Build SQL statement
my $sql = "select ".join(",",@columns).
    " from ".join(",",@tables).
    " where ".join(" and ",@wheres).
    " order by ".join(",",@order_bys);

my $sth = $dbh->prepare($sql);
$sth->execute(@values);

簡單,不需要ORM,非常可定制。 另外,我總是發現ORM對於我正在處理的數據量太重了,但這是另一個主題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM