私は小さなレポートツール(sqliteバックエンド)を開発しようとしています。このツールは「トランザクション」元帳として最もよく説明できます。私がやろうとしていることは、毎週のデータ抽出からの「トランザクション」を追跡することです。
私が持っているのは、私が制御できないレガシーのアーカイブ/レコード管理システムからの毎週のデータ抽出(パイプ区切りのフラットファイル)だけです。
各行は基本的にこれに蒸留することができます:resource_id | resource info | customer_id | customer_info
サンプルデータ:
10| Title X | 1 | Bob
11| Another title | 1 | Bob
10| Title X | 2 | Alice
目標は、(最後のヒットに基づいて)Xか月間使用されていないリソースについて簡単にレポートできるようにすることです。リソースが人気がある場合、アクセスを容易にするためにリソースが保持される保持期間があります。 18か月間使用されていないリソースは、他の場所で長期アーカイブの対象としてマークされています。
これはよくある問題です。データセット間で何が新しい/同じ/削除されたかを判断するための汎用アルゴリズムがあるかどうか(dbと最新の抽出)
さてあなたの答えは...はい。他に必要なものを必要としない、実装可能な単純なアルゴリズムがあります。これは正味現在価値アルゴリズムです。実装は簡単であり、DB側で必要なことは、週ごとのデータに日付スタンプを付けて、1つの単純なクエリと1つの小さな再帰関数またはforループを作成することです。または、これらの他のソリューションのいずれかを実行できます。
NPV = PV-(PV(CP/T)または新しい現在価値は、現在価値に現在の期間(最後のエントリからの月数)を掛けたもの(期間(例:18か月))で割って、リソース値が0になると、正味現在価値になります。費やされています。
あなたが私に欲しい言語を私に与えたら、私は編集でここにコードを投稿します
元の投稿から、取り込んだデータにはトランザクションの日時を示すフィールドがないようですが、ファイルは毎日、毎時などのスケジュールで頻繁に取り込まれていると思います。
これを処理するには、データベースレベルで自動生成されるSQLタイムスタンプ列を追加するか、データを抽出してDBに挿入するコードを使用します。次に、そのタイムスタンプ列にインデックスを配置し、それで完了です。 DBエンジンに、「今回から発生していないトランザクションの数」または「今回からその時間までの間に発生したトランザクションの数」という質問に効率的に答える仕事をさせましょう。
次に、レポートする差分をクエリして計算するジョブをスケジュールします。 「新規」のトランザクションとは、「新規」から要求する日付の前に、DBにレコードがないトランザクションです。古いレコードとは、締切日以降にトランザクションがないレコードです。
代替案:
トランザクションのリストを配列などのある種のデータ構造に解析します。 (C++ではVector
、JavaではArrayList
と考えてください。)
SELECT DISTINCT customer_id FROM Transactions ORDER BY customer_id
などのSQLバックエンドでクエリを実行し、並べ替えられた個別の顧客IDをセットold
にパックします。古いトランザクションと新しいトランザクションをWHERE
句で区切ってまったく同じことを行う場合は、手順3をスキップできます。
新しい更新から一意の顧客IDを、ソートされた順序で別のデータ構造に取得します。データ構造new
を取得するために使用できるデータ構造がいくつかあります。ダブルリンクリストへの挿入ソートは非常に単純ですが、中間ハッシュテーブルを使用すると、ほぼ線形の時間で実行されます。または、とにかく元の配列をソートしている場合は、そのセットを簡単に取得できます。
お好みの言語の標準ライブラリを使用して、セットの違いnew
-old
を取得します。あなたの好きな言語の標準ライブラリにはこのアルゴリズムがありますか?
トランザクションデータベースを更新した後、他に行うことは間違いなくSQLクエリです。
ステップ3に関する注意:データの性質を考慮してください。テキストファイルに注文が時系列でリストされているとします。通常の週に、新しいcustomer_id
が昇順で与えられる多くの初めての顧客がいます。他のほとんどの注文が、少数の忠実なリピート顧客からであり、customer_id
が低いと仮定します。次に、入力はすでにほとんどソートされています。ダブルリンクリストの前に低いcustomer_id
を挿入し、後ろに高いcustomer_id
を挿入しようとする挿入ソートは、その状況では実際にうまく機能します。
あなたの質問からわかるように、実際にはresource_id(+ info)とcustomer(id + info)の「リスト」があります。
したがって、リソースごとの顧客のリストを簡単に保持し、リソースの各リストの最後のノードを確認できます(最後の操作時間を知るために、コードで顧客に日付フィールドを追加するだけです)
私はSQLに慣れていないので、HashMap
とListを使用した例を示しますが、同じ考えだと思います:HashMap <Resource, List<Customer>>
、Resource
にはリソースIDをキーとして含める必要があり、Customer
にはお客様ID、情報、操作日を含める必要があります。
このアイデアを使用すると、前回の操作時間を簡単に把握し、任意のリソースを変更できます(リソースの追加\削除\顧客)。
SqLiteデータベースを使用している場合、バッチの日付をテーブルの列としても追加すると、
10| Title X | 1 | Bob | 2015-03-01
11| Another title | 1 | Bob | 2015-03-01
...............................
10| Title X | 1 | Alice | 2015-03-05
sQLを使用して、過去X日間使用されなかったリソースを取得するのはかなり簡単です。
Select distinct r.ResourceID from Resources r
where not exists (SELECT julianday('now') - julianday(r.DateUpdated)) < X
私はSQLをテストしていませんが、それはあなたにアイデアを与えるはずです
とにかくSQLiteバックエンドで更新を保持している場合は、毎週の更新を新しいテーブルに変換し、それをマージする前にクエリでアーカイブデータと比較できます。
SQLを使用してテーブルへの新しい追加を見つける例: https://stackoverflow.com/questions/2077807/sql-query-to-return-differences-between-two-tables
DBのフィールドにトランザクションの日付が格納されている場合、過去18か月間にトランザクションがあったすべてのユーザーにクエリを実行できます。その場合、アーカイブは完全なDBです。または、まだアクセスしていないすべてのユーザーにクエリを実行し、データを抽出してから削除することもできます。更新は、今週にタイムスタンプが付けられた任意の行です。