![sed を使用して日付ルックアップ ファクト テーブルのロード ファイルを生成することはできますか?](https://rvso.com/image/23958/sed%20%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E6%97%A5%E4%BB%98%E3%83%AB%E3%83%83%E3%82%AF%E3%82%A2%E3%83%83%E3%83%97%20%E3%83%95%E3%82%A1%E3%82%AF%E3%83%88%20%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%AE%E3%83%AD%E3%83%BC%E3%83%89%20%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E7%94%9F%E6%88%90%E3%81%99%E3%82%8B%E3%81%93%E3%81%A8%E3%81%AF%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%81%8B%3F.png)
日付を検索して別の日付を返すために使用される SQL ファクト テーブルがあります。
テーブルスキーマは次のとおりです。
TABLE date_lookup
(
pk_date DATE,
plus1_months DATE,
plus2_months DATE,
plus3_months DATE
);
UNIQUE INDEX on date_lookup(pk_date);
2012 年 1 月 28 日から 2014 年 3 月 31 日までの日付を含むロード ファイル (パイプ区切り) があります。
以下はロード ファイルの例です。
01-28-2012|02-28-2012|03-28-2012|04-28-2012|
01-29-2012|02-29-2012|03-29-2012|04-29-2012|
01-30-2012|02-29-2012|03-30-2012|04-30-2012|
01-31-2012|02-29-2012|03-31-2012|04-30-2012|
...
03-31-2014|04-30-2014|05-31-2014|06-30-2014|
このファクト テーブルのルールは次のとおりです。
IF pk_date has more than 28 days in its month
AND plus1, plus2 or plus3_months only has 28, 29 or 30 days
THEN let plus1, plus2 or plus3 equal the last day of the following month.
私の質問は、ロード ファイルに対して上記のルールに従って 03-31-2014 以降の日付を生成するために を使用することは可能でしょうかsed
、それともこれを実現するプログラムを作成する必要がありますか?
答え1
sed
この場合、それが適切なツールであるかどうかは疑問です。awk
にすでに精通している場合はを使用することをお勧めしますがawk
、そうでない場合はプログラムを作成してください。
私が知っているあるエンジニアは、あなたが言及しているよりもさらに厳しい要件を持つ MSC/NASTRAN 入力ファイルを作成するためにsed
と を使用awk
していましたが、彼はツールに非常に精通していたため、 からの不可解で情報量の少ないエラー メッセージはawk
彼を悩ませませんでした。
これを で実行する場合awk
、入力を前処理して '-' および '|' 文字を削除することをお勧めします。awk
プログラムを別のファイルに記述します。テキスト フィールドの位置 ($1、$2、$3...) を使用し、出力用の SQL INSERT ステートメントを記述します。何度か試行する必要があるため、可能な限り自動化してください。
答え2
技術的には sed で日付演算を行うことは可能ですが、この作業にはまったく適したツールではありません。整数演算が組み込まれている awk や perl などのツールを使用してください。
あなたの要件は日付操作としては珍しいものなので、日付演算をハードコードしたくない場合は、充実した日付操作ライブラリが必要になります。PerlのDate::Manip
のような機能がありますDate_DaysInMonth
。
#!/usr/bin/env perl
use strict;
use warnings;
use Date::Manip;
use List::Util qw(/./);
sub shift_month {
my ($delta, $y, $m, $d) = @_;
$m += $delta;
$y += $m / 12;
$m %= 12;
return ($y, $m, min($d, Date_DaysInMonth($m, $y)));
}
my $next_day = ParseDateDelta("1 day");
my ($cur, $end) = (ParseDate($ARGV[0]), ParseDate($ARGV[1]));
while (Date_Cmp($cur, $end) < 0) {
my @ymd = UnixDate($cur, qw(%Y %m %d));
foreach my $i (0..3) {
printf "%02d-%04d-%02d|", @{[shift_month($i, @ymd)]}[1, 0, 2];
}
$cur = DateCalc($cur, $next_day);
print "\n";
}