固定幅ファイルを解析し、Oracle Dbに基づいて解析された値を見つけます。

固定幅ファイルを解析し、Oracle Dbに基づいて解析された値を見つけます。

ファイルは特定の時間枠(東部標準時の深夜0600)内に到着し、Linuxホストの注文ディレクトリに保存されます。これらのファイルはzip形式で保存されます。通常、この期間中は1日あたり約30個のファイルを受け取ることが予想されます。

この間、追加ファイルも表示され、同じzipファイル名で同じ注文ディレクトリに保存されます。したがって、最初にすべきことは、zipファイルを解凍し、関心のあるファイル(desc1234.NNN)がこれらのzipファイルにあることを確認することです。

次の要件は、ファイル内の特定のフィールド(特定のレコードタイプの場合はファイル内のフィールドの場所:20-34 - 999)の時間到着ウィンドウの後にこれらの30個のファイルをすべて解析することです。ファイルにはいくつかのレコードタイプがあります(他のレコードタイプに加えて)。

これらのファイル(alt_ord_id)で解析されたフィールドを使用して、ord_idOracleデータベースの注文表で特定の列を照会し、ord_idがalt_ord_idとファイル名とともに表示されます。

Oracle Db表の構造は次のとおりです(2つの関心のある列のみが表示されます)。

sql> desc命令;

ord_id varchar2(15); alt_ord_id varchar2(15);

予想される最終O / p:

ファイル名Alt_ord_id Ord_id


desc1234.001 123456789012345 ABCDEFGHIJKLMNO desc1234.002 234567890123456 BCDEFGHIJKLMNOP

これらの毎日のファイルは約30個で、各ファイルには約10〜15個のレコードタイプが含まれており、合計999個があると予想されます。

  • 目次:orders
  • 圧縮ファイル名:customer_orders_YYYYMMDDHHMISS.zip
  • ファイル名:(はシリアル番号desc1234.NNNです)NNN
  • ファイル形式:固定幅テキスト
  1. 次のコマンドを使用して、zipファイルからファイル名を読み取り、ファイルが含まれていることを確認します。desc1234.NNN

    for zip_file in *.zip; do if [$(unzip -l $zip_file|grep -c "desc1234") -ne 0]; then filename="`zipinfo -1 customer_orders.zip`"; echo $filename; fi; done
    

    出力:

    desc1234.001
    
  2. コマンド#2

    cat desc1234.123|grep "999"|cut -c 20-34|awk 'BEGIN {printf("(")} (for i=1; i<=NF;i++) { printf("'\''%s'\'',",$i} } '|awk '{gsub(/,$/,")"}; print}'> test2.txt
    

    出力:

    ('123456789012345','234567890123456','345678901234567')
    

最後の文字列を送信するには、上記の(1)と(2)を組み合わせる必要があるようです。

('123456789012345','234567890123456','345678901234567') 

Oracleデータベースでテーブルを見つけます。

午前12時から午前6時の間に処理されたファイルを見つけるとき(1)と(2)の組み合わせを取得するにはどうすればよいですか?

入力ファイル:

001ORDERS20211117   72222 ORDERS CYCLE 001 202111170320
001 124 ABC XYZ
002 231 WASHING CYCLE
999 456 YUIHY      123456789012345  
011 123 ABCD XYZ
012 786 MACHINE
999 654            234567890123456

説明1234.001

ベストアンサー1

開始点として以下のスクリプトを試してみてください。

awkところで、どのタイプのUNIXを実行しているのか、どのシェルを使用しているのか、どのバージョンを使用しているのかは明らかではありませんでした。私はあなたがLinux(またはGNUコアユーティリティがインストールされている他のシステム)、bash、およびGNU awkを実行していると仮定します。しかも情報圧縮unzipこれらの仮定が間違っている場合は、システムに合わせてbash + awkスクリプトを調整する必要があります。

$ cat process-zip-files.sh 
#!/bin/bash

# create a temporary directory
# mktemp is in GNU coreutils
td="$(mktemp -d)"

for zf in *.zip; do
  # unzip options: -qq = very quiet, -o = don't prompt for overwrite,
  # -d = directory to unzip files into.
  unzip -qq -o -d "$td" "$zf" '*.[0-9][0-9][0-9]'
done

# Process each unzipped text file individually
# This awk script requires GNU awk.  The ENDFILE pattern
# is a GNU extension to awk.
awk '/^999 / { data[i++] = substr($0,20,34) };

     ENDFILE {
       out="";
       for (i in data) { out = out data[i] "," };
       sub(/,$/,"",out);
       print "(" out ")";
       delete data;
     }' "$td/"*

# delete the temporary directory and everything in it
rm -rf "$td/"

999このスクリプトは、各テキストファイルに少なくとも1つのレコードがあると仮定します。そうでない場合は、配列のENDFILEブロックに1つ以上の要素があることを確認する必要があります。それ以外の場合は、そのテキストファイルに対して1行だけ出力されますdata()

これは、エラーの確認や処理を行わず、例外や複雑な状況を処理しようとしない最小限のスクリプトです。

出力例(例テキストを含むzipファイルを作成した後):

$ ./process-zip-files.sh 
(123456789012345,234567890123456)

より良いスクリプトはを使用することですperl。これにより、Oracleデータベースへの接続が確立されます(openを使用して)。データベースインタフェースそしてDBD::Oracle

次に、今日のzipファイルのバッチを開きます(次を使用)。アーカイブ::郵便番号モジュール)とその中の各.NNNテキストファイルを処理します。テキストファイルのデータを使用してSQL文を構成し、それをOracle DBに送信します。

ステートメントは、検索、挿入、更新、削除など、通常SQLを使用して実行できるすべての操作です。

pythonもう一つの良い実装言語になります。 Oracleなどのデータベースやzipファイルと対話するためのライブラリモジュールもあります。

そこはいBashや他のシェルからOracleや他のSQLデータベースと直接対話する方法があります。しかし、必要なスペースと引用の量が多すぎるため、迷惑で退屈で小さな問題が発生しやすいプログラミング作業です。タスクを実行するために必要な最小限のPerl(またはPython)サブセットを学ぶのははるかに簡単です...そして一度実行した後は、後で同様のタスクを簡単に実行できます。

ほとんど午前2時で寝る必要があるため、この時点ではそのようなスクリプトの基本バージョンを作成する時間さえありません。とにかく、あなたの質問は、Oracleがデータを処理する方法の詳細を実際に提供していません。


PS:あなたの質問に投稿した2つのシェルコードの例を見ると、1行のコードで何かをするのが好きだと思います。 Quipは便利ですが、常に問題に対する最善の解決策ではなく、一般的に悪い解決策です。 awkやPerlなどの言語でスクリプトを書くのを恐れないでください。スタンドアロンとして使用するか、シェルスクリプトの一部としてスクリプトを使用することは、UnixとLinuxを使用する方法です。

多くのコマンドで構成された長く複雑なパイプラインを使用してシェルでデータを処理しようとすると、awkまたはPerlでカスタムツールを作成するよりもはるかに難しくなり、シェルパイプラインが脆弱になる可能性があります。確かに数倍遅くなります。小さなデータファイルと単純な処理操作の場合、パフォーマンスは重要ではない可能性があります。大量のデータおよび/または複雑な処理の場合、これは実行時間が数秒から数時間の間の差を意味する可能性があります。


Archive::Zip以下は、PerlでDBI同じタスクを実行するためにand /または&モジュールを使用するいくつかの例ですDBD。これらのPerlスクリプトは.zipアーカイブから直接一致するファイルを読み取るため、.zipファイルを抽出する一時ディレクトリは必要ありません。

最初の例では、bash + awkスクリプトの機能を複製します。

$ cat process-zip-files.pl
#!/usr/bin/perl

use strict;

use Archive::Zip;

# First arg is the source directory. defaults to ./
my $dir = shift // '.';

foreach my $zf (glob "$dir/*.zip") {
  # open the zip file
  my $zip = Archive::Zip->new($zf);

  # get the list of files ending with a dot and at least one digit
  my @txt = grep { /\.\d+$/ } $zip->memberNames();

  # iterate over each matching filename
  foreach my $f (@txt) {
    my @data = ();

    # Iterate over each line of the file ($f).  This code is fine
    # for smallish files, but it would be better to use the
    # Archive::Zip::MemberRead module for large files to avoid
    # reading the entire file into memory at once.
    foreach (split /\n/, $zip->contents($f)) {
      if (m/^999\s/) {
        # perl substr offsets start at 0, not 1.  So the
        # next line grabs 15 chars, starting from char 20
        # and adds the string to the @data array.
        push @data, substr($_,19,15);
      }
    };

    # Now do something with the data from this file
    @data = map { "'$_'" } @data; # quote each element of @data
    print "(", join(",",@data), ")\n";

  }  # end of current member file
} # end of current zipfile
$ ./process-zip-files.pl 
('123456789012345','234567890123456')

単にデータを印刷する代わりに、データベースと直接対話することができます。ここでは、あいまいでやや役に立たない例だけを提示します。なぜなら、データベーステーブル構造が何であるか、.NNNファイルから抽出されたデータで実際に何をしたいのかわからないからです。

$ cat process-zip-files-sql.pl
#!/usr/bin/perl

use strict;

use Archive::Zip;
use Archive::Zip::MemberRead;
use DBI;

# First arg is the source directory. defaults to ./
my $dir = shift // '.';

# I don't have Oracle, and I couldn't be bothered setting up
# a database, table, and login account on mysql or postgres
# for this example, so I'll use SQLite.  Other databases are
# just as easy to connect to, but the connect() call will
# require other details like hostname, port, login, password,
# etc.
#
# Set up a database handle ($dbh) to the sqlite db called
# "notoracle.sqlite3":

my $dbname='notoracle.sqlite3';
my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname","","");

foreach my $zf (glob "$dir/*.zip") {
  my $zip = Archive::Zip->new($zf);
  my @txt = grep { /\.\d+$/ } $zip->memberNames();

  foreach my $f (@txt) {
    my @data = ();

    # This example uses Archive::Zip::MemberRead, just to show
    # how to use it.
    my $fh  = Archive::Zip::MemberRead->new($zip, $f);
    while (defined(my $l = $fh->getline())) {
      if ($l =~ m/^999\s/) {
        push @data, substr($l,19,15);
      }
    };
    $fh->close();

    # Example 1: print matching records (each element needs to be
    # quoted when using IN, can't use placeholders):

    my @qdata = map { "'$_'" } @data; # quote each element of @data
    my $values = join(",",@qdata);
    my $sql = "select * from mytable where myfield in ($values)";
    print join(",", $dbh->selectrow_array($sql)),"\n";

    # Example 2 - using a placeholder ?, one element of @data
    # at a time.  There is no need to quote each element of
    # the @data array because placeholders handle quoting
    # automagically if and when required, depending on the data
    # type of the database field.

    my $sth = $dbh->prepare('select * from mytable where myfield = ?');
    foreach my $d (@data) {
      while (my @row = $sth->fetchrow_array($sql,undef,$d)) {
        print join(",",@row), "\n";
      }
    }
  }  # end of current member file
} # end of current zipfile

この例は機能的ではない概念的な例なので、出力例はありません。同じ理由で、このコードはテストされておらず、マイナーなバグが含まれる可能性があります。うまくコンパイルされていますが、perl -w -c process-zip-files-sql.pl実際に機能したり便利なことをするという保証はありません。

おすすめ記事