ITエンジニアの成長ブログ

ITエンジニアとして行う勉強の発信&日々の生活で体験した楽しいことをゆるく発信

SimpleDateFormatの文字列型→日付型の変換について

Javaで文字列として取得した日付を、日付型に変換するためにSimpleDateFormatを使用する方法がありますが、このSimpleDateFormatの扱いには注意が必要です。

例えば、以下のように本来存在しない日付(2024/02/31)でフォーマットすると良からぬことが起きます。

DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
System.out.println(sdf.parse("2024/02/31"));

実行結果は以下の通りです。

Sat Mar 02 00:00:00 JST 2024

エラーにはならずに、勝手に(2024/03/02)に解釈されます。

上記のような挙動をこれで良しとするケースはおそらくないと思います。

このような挙動を防ぐには、フォーマット変換のメソッド呼び出しの前に、DateFormatのsetLenientメソッドにfalseを渡して呼び出しておきます。そして、フォーマット変換メソッドを実行すると、異常な変換となる場合は例外をスローしてくれます。

DateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
sdf.setLenient(false);
System.out.println(sdf.parse("2024/02/31"));

実行結果は以下の通りです。

Exception in thread "main" java.text.ParseException: Unparseable date: "2024/02/31"
	at java.base/java.text.DateFormat.parse(DateFormat.java:403)
	at Sample.main(Sample.java:9)


JavaDocのリンクも張っておきます。
DateFormat (Java SE 23 & JDK 23)

上記の通り、異常な場合は例外をスローしてくれるので意図しない値で後続処理が実行されるのを防いでくれるという感じです。

実は最近まで上記の機能を知らなくて、正常な月末日を取得しなければいけない場合において、以下のようにjava.util.Calendarクラスを使用してました。

int year = 2024;
int month = 2;

Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DAY_OF_MONTH));

System.out.println(cal.getTime());

異常な値で後続処理が実行されることを防ぐと同時に、それを自動的に補正するようなプログラムを作成していました。ケースバイケースだとは思いますが、本来ならば異常な値が渡されたら例外をスローするのが良さそうですよね。

結論としては、SimpleDateFormatで文字列から日付型変換する場合は、setLenientを呼び出すのがマストになってきそうですね。
今回はこの辺で。最後までお読みいただきありがとうございました。

IDENTITYプロパティを初期化する方法

SQL ServerでIDENTITYプロパティを初期化する方法が気になったので調べました。

サンプルテーブル

以下のサンプルテーブルで、IDENTITYプロパティを初期化する方法を実際に確認したいと思います。

CREATE TABLE [dbo].[Table_1](
	[num] [tinyint] IDENTITY(1,1) NOT NULL
)

IDENTITYプロパティを初期化する状況

IDENTITYプロパティを初期化する状況を疑似的に作りたいと思います。

上記サンプルテーブルの「num」のtinyintの最大値まで連番が付与されたケースを考えます。tinyintは255が最大値になりますので、このテーブルの「num」列に1~255の値がそれぞれ別レコードで登録されている状況にしておきます。

IDENTITYプロパティをカラムの最大値まで連番を付与

上記状況で、以下のようにそれ以上の連番生成を行った場合はエラーになります。

連番生成エラー

これだとこれ以上データを挿入できないので、IDENTITYプロパティの連番を初期化したいですね。以下でそのやり方を確認します。

IDENTITYプロパティを初期化する方法

以下のSQLコマンドを使用することで初期化できます。
DBCC CHECKIDENT (Transact-SQL) - SQL Server | Microsoft Learn

1つ目の引数がテーブル名、2つ目の引数は「RESEED」固定、3つ目の引数は初期化する値を指定します。今回は初期化後の値が1となってほしいので、初期化する値は0としました。

DBCC CHECKIDENT ('[dbo].[Table_1]', RESEED, 0);
初期化する方法

上記クエリで初期化したので、以下の通りINSERTが正常に実行できるようになりました。

初期化後にテーブルへレコードを登録

0に初期化したので、上記のINSERT処理でサンプルテーブルには、numの値が1のデータが2つ存在する状況となりました。

テーブルに初期化後のデータが正常に登録されている様子

補足

因みに、テーブルのデータをTRUNCATEするとIDENTITYプロパティは初期化されるみたいです。合わせて知っておくと良さそうです。

TRUNCATE TABLE [dbo].[Table_1]

おわりに

いかがでしたでしょうか。本来はこのような初期化を手動で実行する状況は好ましくはないのかもしれませんが、知識として知っておいた方が良さそうなので調べました。

今回はこの辺で。最後までお読みいただきありがとうございました。

データベースのテーブルに定義する更新ログ列について

今回は、データベースのテーブルに定義する更新ログ列について簡単にまとめたいと思います。

データベースのテーブルに定義する更新ログ列とは?

この記事において更新ログ列とは、テーブルに定義する以下のようなカラムのことを示しています。

  • 更新日時
  • 更新者
  • 作成日時
  • 作成者

レコードの作成時や更新時にこれらのカラムを更新することで、データがいつ更新されたレコードなのか、誰が更新したのかをログとして記録することができます。

これらの情報がないと、誰がいつ該当のデータを更新したのかが追跡できないので、調査をする場合にかなり不便になったりします。

個人的な設計方針

更新ログ列として、個人的な設計方針を示したいと思います。

私は、以下のカラムをすべてのテーブルに定義します。それぞれ、個別に見ていきます。

  • 更新日時
  • 更新者
  • 作成日時
  • 作成者
  • æ›´æ–°PGM
  • 作成PGM
更新日時

更新日時は、レコードを更新するときに必ずセットで更新するカラムです。更新タイミングのシステム日時を登録します。レコードの新規登録時も登録するようにします。ただし、これはデフォルト制約でシステム日時を登録するようにしておけば良いですね。

更新者

更新者は、該当のデータを更新したユーザーの名前を登録します。ユーザーには、一般的にIDが付与されるため、本項目にそのIDかそれとも、名前そのものを登録するか悩むところですが、個人的には名前を登録する方が良いかなと思っています。なぜならば、IDだといちいちユーザーIDから名前を確認する作業が必要になるからです(ただし名前は変わることもあるので、それらを加味する必要はありますが、かなりイレギュラーなので名前登録派です)。

作成日時

作成日時は、レコードを登録するときにシステム日時を設定します。その後は一度も更新しません。あくまでもそのレコードがいつ登録されたのかのみを保持しておく項目になります。

作成者

作成者は、該当のデータを作成したユーザーの名前を登録します。その後は一度も更新しません。設定する値は、「更新者」と同様です。

æ›´æ–°PGM

更新PGMは、更新したプログラムの名前を設定します。例えば、受注入力画面で登録した受注データの場合は、更新PGMに「受注入力」といった感じで設定します。

作成PGM

作成PGMは、作成したプログラムの名前を設定します。登録後は一度も更新しません。設定する値は、「更新PGM」と同様です。


基本的には、上記のカラムを私は定義するようにしています。

これはあくまでも私の考えなので設計する人によって色々とあると思います。例えば、これらのカラムを全く定義しない人もいるし、作成日時や作成者は作らず、更新日時や更新者のみを登録する人もいます。

また、重要と思われるテーブルのみ設定しておくというのも考え方としてはあります。

本当に設計者の考えが色々と現れるところだなと思います。色々なシステムの設計を見てみたいものです。

おわりに

いかがでしたでしょうか。個人的な経験から、テーブルに定義する更新ログに何を用意しておくかを確認しました。

対応するシステムによっては、ここまで厳密にする必要もないのかもしれませんので、上記の考え方はあくまで一例です。そのシステムごとに必要に応じて考える必要があると思います。

今回はこの辺で。最後までお読みいただきありがとうございました。

SQL Serverでは、行値式が使えない

SQL Serverでは”行値式”が使えません。

行値式とは、以下のように使えるSQLの構文を言います。

WHERE (col1, col2) IN (
  (A, B), (C, D)
)

上記で何となくわかるかと思いますが、複数のカラムの値を条件にして、特定のレコードを取得することができます。

上記の構文の意味は、日本語にすると(col1がA 且つ、col2がB)または(col1がC 且つ、col2がD)のレコードを取得するという条件になります。

このSQLの構文が、どうやらSQL Serverでは使えないようです。構文エラーになります。

じゃあ、上記のような条件をSQL Serverで表す場合はどうすればよいのかとなりますが、以下のように対応できると思います。

WHERE (col1 = A AND col2 = B) OR (col1 = C AND col2 = D)

IN句の条件で抽出する値が、上記のようなリテラル値ではなく、他のテーブルの値であれば、以下のようにEXISTS句を使うのが良さそうです。

SELECT * FROM t1 WHERE EXISTS (
    SELECT * FROM t2 WHERE t1.col1 = t2.col1 AND t1.col2 = t2.col2
)

おわりに

SQL Serverは、行値式が使えないことを最近知りましたのでメモ程度に記事にしました。

使えないからと言って、極端に面倒なことにはならないので個人的にはあまり気にしていません。

しかし、行値式について書いた皆様方のブログ記事を見ると、どうやらこの構文はSQL標準らしいので、それを対応していないのはちょっとな~という気持ちもあります。

因みに、OracleやPostgreSQLなどは行値式使えるようですね。SQLは標準が定義されてはいますが、このように製品によってブレはあるので、その都度調べながら使う必要があるのが少し大変です。

今回はこの辺で。最後までお読みいただきありがとうございました。

Excelのセルの書式が文字列から数値に変更されない

今回は、Excelの話題です。

あまり需要がないかもしれませんが、個人的に操作時にかなり煩わしかったので、今回対処方法を調べました。よろしければお読みください。

今回使用するのは、Microsoft 365のExcelバージョン2406です。おそらく、他のバージョンでも同様の手順で動作すると思いますがお手元の環境では同じように動作しない場合があることもご了承ください。

「セルの書式が文字列から数値に変更されない」とは?

Excelで以下のように見た目は数値だけれど、セルの書式としては文字列に設定している以下のような値があります。

Excelのキャプチャ

当たり前ですが、このセルは文字列に設定されているので、数値を対象に動作するSUM関数を使用することはできません。

SUM関数を入力している様子

実際にSUM関数を使用してみると、以下の通り正常に機能しないことが分かります。

SUM関数が正常に機能していない様子

SUM関数が正常に機能するように、セルの書式を文字列→標準に変更します。以下の通り対象のセルを選択し、ホームタブの数値欄の書式を標準にします。

セルの書式を標準に変更する

しかし、セルの書式は確かに標準に変更されているけれど、SUM関数は以前として機能していません。このようにセルの書式を変更しただけでは、そのセルの書式は変わりません。これが今回言及している事象です。

セルを標準に変更したけれど、SUM関数が機能しない

セルの書式を文字列から数値に正しく変更する

上記の通り、セルの書式を変更しただけでは上手くセルの値が変わってくれません。

もちろん、対処方法はあって以下のようにセルの値を一度フォーカスして再度フォーカスを外すと、セルの値が変わります。

セルB2にフォーカスしている様子

上記操作を実行した様子は以下の通りです。セルの値は右寄せになり、セルの左端の緑のマークが消えました。そして、注目すべきはSUM関数にその数値が反映されています。このような操作をすることで、文字列から数値に変更することができます。

セルB2にフォーカスした後、フォーカスを外した様子

しかし、これで対処ができるのですが、対象のセルが多いとかなり面倒です。今回は3つだけですが、これが10個とかそれ以上となると、最初からシートを新しくした方が現実的でしょう。

この面倒な変換を一度にまとめて実行する方法があります。

セルの書式を文字列から数値にまとめて実行する方法

セルの書式を文字列から数値にまとめて実行する方法のやり方を紹介します。

書式を文字列から数値に変更したいセルを選択します。すると以下の通り、セルの左上当たりに三角の警告マークが表示されます。

書式変更したいセルを選択している様子

この三角の警告マークにカーソルを当てると、クリックできるのでクリックします。すると、以下の通りポップアップが表示されます。「数値が文字列として保存されています」というメッセージが見えますね。

三角の警告マークをクリックした様子

そうしたら、このポップアップの「数値に変換する」を選択します。すると、以下の通り一発で変換されます。SUM関数も正常に機能しています。これで完了です。

「数値に変換する」でまとめて変換している様子

おわりに

いかがでしたでしょうか。Excelの細かいtipsですが、毎日Excelをガンガン使用する場合は、このような一つ一つの工夫が大事かなと思います。今後もこのような便利なtipsがあれば、紹介していきたいと思います。

因みに、今回の挙動は私の調べた限りだとどうやらExcelの仕様?のようです。参考にMicrosoftのリンクを添付していますが、回避策として情報を提供してくれていますが、それをバグだと言及しているような節は特にありません。

何かしら理由があるのかもしれません。理由を誰か知っている方がおりましたら、教えていただければ幸いです。

今回はこの辺で。最後までお読みいただきありがとうございました。

Subversionのマージについて

「バージョン管理システム」と言えば、最近は専らGitが使われることが多いと思いますが、今回はSubversionにおけるマージのメモを残しておきます。

メモを残す理由としては、日本語のドキュメントが少ないことやマージの処理がバージョンで色々と変わっていたりして、分かりづらいと感じたからです。この記事ではマージに大きく関係する機能の追加や変更について気になる部分を抜粋して紹介します。

しかし、あくまで個人的に使用して確認したわけではないため(ブログ記事や各種ドキュメントを確認)、もしかしたら誤りがあるかもしれません。その点はご了承くださいませ。

バージョン1.5前のマージ

バージョン1.5より前のバージョンでは、マージするときにはマージする範囲のリビジョンを明示的に指定する必要がありました。

そのため、どのリビジョンをマージしたかを忘れないように(後から見てわかるように)、マージするコミットログにそのリビジョンをメモしておくことが重要でした。

そうしておかないと、複数回同じリビジョンをマージしてしまったりと、かなりやっかいな事象が発生してしまうことがあったそうです。

バージョン1.5~1.7のマージ

バージョン1.5でMerge Tracking機能が追加されました。

これにより、バージョン1.5前のマージでリビジョンを正確に覚えて、マージ実行時に指定する必要がなくなりました。なぜならば、mergeinfoというSVNプロパティを使ってSubversion自体がマージのリビジョンを管理してくれるようになったからです。

バージョン1.8のマージ

このバージョンでは、Automatic reintegration mergeと呼ばれる機能が追加されました。

これは、SVNのマージコマンドにおける「--reintegrate」オプションと関係があります。

このオプションは、trunkから分岐したbranchを開発が終了した段階で、trunkに戻すときに付与するオプションです。このオプションを指定しないと、不要なリビジョンまでtrunkにマージしてしまうことになり、バージョン1.7までは必須でした。

しかし、バージョン1.8からはこのオプション「--reintegrate」は不要になりました。Subversion側でその動作を必要とする場合は、自動で判断してマージしてくれるようになりました。

おわりに

いかがでしたでしょうか。Subversionの操作方法を調べてみると、かなり昔のものも多くあり現在では必要のない手順やオプションが散見していました。

個人的にもまだしっくりきていない部分も多いので、都度知識をUPDATEしていきたと思います。

今回は、この辺で。最後までお読みいただきありがとうございました。

SQL Serverの復旧モデルとは?

今回は、SQL Serverの復旧モデルについてお話したいと思います。今回は、あくまで概要のみ説明します。

SQL Serverの復旧モデルとは?

復旧モデルとは簡単に言えば、データベースのバックアップをどのようなポリシーで実施するかを決めるためのモデルとなります。

復旧モデルは、以下の3つから選択することができます。

  • 単純
  • 完全
  • 一括ログ

復旧モデルは、データベースのプロパティとして個々のデータベース毎に設定することができます。SSMSでは以下の箇所で設定することができます。ここでは、「完全」が選択されています。

SSMSで復旧モデルを確認する

以降で、個々の復旧モデルの概要を説明します。今回は、「単純」と「完全」のみ説明します。
※「一括ログ」はやや特殊なので今回は割愛します

復旧モデル「単純」とは?

単純復旧モデルは、3つの中で最もシンプルなモデルとなります。

このモデルを使用する場合は、データベースの復元はバックアップ取得タイミングとなります。そのため、バックアップを取得しておかなければバックアップ取得後に更新されたデータベースへの変更は失われます。

「特定のポイントで取得したバックアップタイミングの時点に戻ることができれば良い」、というような運用であればこのモデルを採用します。

それが許容できない場合は、次の「完全」を選択します。

復旧モデル「完全」とは?

バックアップを取得したタイミングのみではなく、障害発生した直前のポイントまで復元したい場合はこの「完全」復旧モデルを選択します。

このモデルでは、リアルタイミングで発生する更新情報を記録したログバックアップを利用して、たとえば障害発生した直前のポイントへ復元することができるような仕組みを実現します。

多くのユーザーが使用するような重要なシステムの場合は、おそらくこちらを採用することになるかと思います。

因みに、この「完全」がデフォルトの復旧モデルとなっています。

まとめ

いかがでしたでしょうか。SQL Serverの復旧モデルについて簡単にお話してきました。

正直、概要のみでこれだけでは運用するうえで必要な知識は何も得ることができないと思いますが、とりあえずの導入として記事を書きました。

万が一データベースに障害が発生して、特定のタイミングに戻したいとなったときに復旧モデル「単純」だと、それを実現することができません。そんな恐ろしい事態に直面する前に、事前に設定項目を理解して設定しておきたいものです。

今回はこの辺で。最後までお読みいただきありがとうございました。