SQLをVBで扱う。(2)
テーマ:Windows
2010年08月12日 08時49分
前回の記事:SQLをVBで扱う。(1)
ここまでで、VB上ではただの文字列として処理されていたSQLが、
関数という形で意味を持つものになりました。
しかしまだ不完全です。数式がただの文字列のままです。
そこで数式クラスを作成し、オペレータオーバーロードを使用することにより、
VBでの数式をSQLの数式に変換します。論より証拠でコードを示します。
上記コードを実行すると
が出力されます。つまり、"a + b" と言うコードから "a + b"と言う文字列が生成された訳です。
ただ、このままではいちいち New したりと使い勝手が良くありません。
そこで、暗黙の型変換を使用して記述をしやすくします。
String及びIntegerはExprオブジェクトに自動で変換される様になりました。
また、Exprオブジェクトは自動で文字列に変換される様になりました。
結果、より素直な記述が可能になりました。
Exprクラスが出来たことにより、VBでの数式から「数式の文字列」を生成する事が出来るようになりました。
先に作成したSQLクラスと組み合わせて、最初のSQLを記述してみます。
元はただの文字列であったSQLが、見事にVBのコードと化しました。
と同時に、VBとSQLの両方を知っている人でも、内容を理解しづらいコードとなりました(笑)。
最後に、SQLクラスとExprクラスの全コードを掲載しておきます。
注意!!
この記事を参考にコードを書いて上司に叱られても、当方は一切関知しません。
ここまでで、VB上ではただの文字列として処理されていたSQLが、
関数という形で意味を持つものになりました。
しかしまだ不完全です。数式がただの文字列のままです。
そこで数式クラスを作成し、オペレータオーバーロードを使用することにより、
VBでの数式をSQLの数式に変換します。論より証拠でコードを示します。
Class Expr
Dim s As String = ""
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Shared Operator +(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("{0} + {1}", a.s, b.s))
End Operator
End Class
Dim a as New Expr("a")
Dim b as New Expr("b")
Dim c as Expr = a + b '← ここ!!
Debug.Print(c.s)
Dim s As String = ""
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Shared Operator +(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("{0} + {1}", a.s, b.s))
End Operator
End Class
Dim a as New Expr("a")
Dim b as New Expr("b")
Dim c as Expr = a + b '← ここ!!
Debug.Print(c.s)
上記コードを実行すると
a + b
が出力されます。つまり、"a + b" と言うコードから "a + b"と言う文字列が生成された訳です。
ただ、このままではいちいち New したりと使い勝手が良くありません。
そこで、暗黙の型変換を使用して記述をしやすくします。
Class Expr
Dim s As String = ""
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Shared Operator +(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("{0} + {1}", a.s, b.s))
End Operator
Public Shared Widening Operator CType(ByVal s As String) As Expr
Return New Expr(s)
End Operator
Public Shared Widening Operator CType(ByVal s As Integer) As Expr
Return New Expr(s.ToString)
End Operator
Public Shared Widening Operator CType(ByVal e As Expr) As String
Return e.s
End Operator
End Class
Dim a as New Expr("a")
Debug.Print(a + "b") '← ここ!!
Dim s As String = ""
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Shared Operator +(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("{0} + {1}", a.s, b.s))
End Operator
Public Shared Widening Operator CType(ByVal s As String) As Expr
Return New Expr(s)
End Operator
Public Shared Widening Operator CType(ByVal s As Integer) As Expr
Return New Expr(s.ToString)
End Operator
Public Shared Widening Operator CType(ByVal e As Expr) As String
Return e.s
End Operator
End Class
Dim a as New Expr("a")
Debug.Print(a + "b") '← ここ!!
String及びIntegerはExprオブジェクトに自動で変換される様になりました。
また、Exprオブジェクトは自動で文字列に変換される様になりました。
結果、より素直な記述が可能になりました。
Exprクラスが出来たことにより、VBでの数式から「数式の文字列」を生成する事が出来るようになりました。
先に作成したSQLクラスと組み合わせて、最初のSQLを記述してみます。
Dim estimateCusId As New Expr("見積.顧客ID")
Dim CusId As New Expr("顧客.顧客ID")
Dim money As New Expr("見積詳細.金額")
Dim estimateId As New Expr("見積.見積ID")
Dim detailId As New Expr("見積詳細.見積ID")
q = New SQL
q.Select("見積ID", "顧客名", money.Sum())
q.From("見積")
q.Join("顧客", estimateCusId = CusId)
q.Join("見積詳細", estimateId = detailId)
q.Where(estimateId >= 100 And money >= 0)
q.GroupBy("見積ID", "顧客名")
q.Having(money.Sum >= 100)
Debug.Print(q)
Dim CusId As New Expr("顧客.顧客ID")
Dim money As New Expr("見積詳細.金額")
Dim estimateId As New Expr("見積.見積ID")
Dim detailId As New Expr("見積詳細.見積ID")
q = New SQL
q.Select("見積ID", "顧客名", money.Sum())
q.From("見積")
q.Join("顧客", estimateCusId = CusId)
q.Join("見積詳細", estimateId = detailId)
q.Where(estimateId >= 100 And money >= 0)
q.GroupBy("見積ID", "顧客名")
q.Having(money.Sum >= 100)
Debug.Print(q)
元はただの文字列であったSQLが、見事にVBのコードと化しました。
と同時に、VBとSQLの両方を知っている人でも、内容を理解しづらいコードとなりました(笑)。
最後に、SQLクラスとExprクラスの全コードを掲載しておきます。
Class SQL
Dim s As String = ""
Public Sub New()
End Sub
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Function [Select](ByVal ParamArray arg() As String) As SQL
Me.s &= " Select " & String.Join(",", arg)
Return Me
End Function
Public Function From(ByVal arg As String) As SQL
Me.s &= " From " & arg
Return Me
End Function
Public Function Where(ByVal arg As String) As SQL
Me.s &= " Where " & arg
Return Me
End Function
Public Function Union(ByVal arg As String) As SQL
Me.s &= " Union " & arg
Return Me
End Function
Public Function OrderBy(ByVal arg As String) As SQL
Me.s &= " Order By " & arg
Return Me
End Function
Public Function Join(ByVal t As String, ByVal expr As String) As SQL
Me.s &= " Join " & t & " on " & expr
Return Me
End Function
Public Function GroupBy(ByVal ParamArray arg() As String) As SQL
Me.s &= " Group By " & String.Join(",", arg)
Return Me
End Function
Public Function Having(ByVal arg As String) As SQL
Me.s &= " Having " & arg
Return Me
End Function
Public Shared Widening Operator CType(ByVal a As SQL) As String
Return a.s
End Operator
End Class
Class Expr
Dim s As String = ""
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Shared Operator +(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} + {1})", a.s, b.s))
End Operator
Public Shared Operator -(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} - {1})", a.s, b.s))
End Operator
Public Shared Operator =(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} = {1})", a.s, b.s))
End Operator
Public Shared Operator <>(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} <> {1})", a.s, b.s))
End Operator
Public Shared Operator >=(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} >= {1})", a.s, b.s))
End Operator
Public Shared Operator <=(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} <= {1})", a.s, b.s))
End Operator
Public Shared Operator And(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} and {1})", a.s, b.s))
End Operator
Public Function Sum() As Expr
Return New Expr(String.Format("sum({0})", Me.s))
End Function
Public Shared Widening Operator CType(ByVal s As String) As Expr
Return New Expr(s)
End Operator
Public Shared Widening Operator CType(ByVal s As Integer) As Expr
Return New Expr(s.ToString)
End Operator
Public Shared Widening Operator CType(ByVal e As Expr) As String
Return e.s
End Operator
End Class
Dim s As String = ""
Public Sub New()
End Sub
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Function [Select](ByVal ParamArray arg() As String) As SQL
Me.s &= " Select " & String.Join(",", arg)
Return Me
End Function
Public Function From(ByVal arg As String) As SQL
Me.s &= " From " & arg
Return Me
End Function
Public Function Where(ByVal arg As String) As SQL
Me.s &= " Where " & arg
Return Me
End Function
Public Function Union(ByVal arg As String) As SQL
Me.s &= " Union " & arg
Return Me
End Function
Public Function OrderBy(ByVal arg As String) As SQL
Me.s &= " Order By " & arg
Return Me
End Function
Public Function Join(ByVal t As String, ByVal expr As String) As SQL
Me.s &= " Join " & t & " on " & expr
Return Me
End Function
Public Function GroupBy(ByVal ParamArray arg() As String) As SQL
Me.s &= " Group By " & String.Join(",", arg)
Return Me
End Function
Public Function Having(ByVal arg As String) As SQL
Me.s &= " Having " & arg
Return Me
End Function
Public Shared Widening Operator CType(ByVal a As SQL) As String
Return a.s
End Operator
End Class
Class Expr
Dim s As String = ""
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Shared Operator +(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} + {1})", a.s, b.s))
End Operator
Public Shared Operator -(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} - {1})", a.s, b.s))
End Operator
Public Shared Operator =(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} = {1})", a.s, b.s))
End Operator
Public Shared Operator <>(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} <> {1})", a.s, b.s))
End Operator
Public Shared Operator >=(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} >= {1})", a.s, b.s))
End Operator
Public Shared Operator <=(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} <= {1})", a.s, b.s))
End Operator
Public Shared Operator And(ByVal a As Expr, ByVal b As Expr) As Expr
Return New Expr(String.Format("({0} and {1})", a.s, b.s))
End Operator
Public Function Sum() As Expr
Return New Expr(String.Format("sum({0})", Me.s))
End Function
Public Shared Widening Operator CType(ByVal s As String) As Expr
Return New Expr(s)
End Operator
Public Shared Widening Operator CType(ByVal s As Integer) As Expr
Return New Expr(s.ToString)
End Operator
Public Shared Widening Operator CType(ByVal e As Expr) As String
Return e.s
End Operator
End Class
注意!!
この記事を参考にコードを書いて上司に叱られても、当方は一切関知しません。
イイ!と思ったら拍手をお願いします↓
SQLをVBで扱う。(1)
テーマ:Windows
2010年01月08日 22時56分
SQLをVBで扱う。
VBでDBを操作していると、動的にSQLを生成する場面がたまに出てきます。
それを、効率よく行う方法を、(半分ネタで)考えてみました。
VBでSQLを扱う場合、普通は次のような感じでしょうか。
これではいけません。ただの文字列ではなく、意味を持たせましょう。
そのために次のようなクラスを作成しました。
足りないSQL句を実装して最初の例を記述すると次のようになりました。
(SQLクラスの全ソースは次回に記載します。)
行を分けずに書けばこんな感じです(うげ~)
次回に続きます。
VBでDBを操作していると、動的にSQLを生成する場面がたまに出てきます。
それを、効率よく行う方法を、(半分ネタで)考えてみました。
VBでSQLを扱う場合、普通は次のような感じでしょうか。
Dim s As String = ""
s &= "Select 見積ID,顧客名,sum(見積詳細.金額) "
s &= " From 見積 Join 顧客 on 見積.顧客ID=顧客.顧客ID Join 見積詳細 on 見積.見積ID=見積詳細.見積ID "
s &= " Where 見積ID>=100 and 見積詳細.金額>=0"
s &= " Group By 見積ID,顧客名 "
s &= " Having sum(見積詳細.金額)>=100"
Debug.Print(s)
ここでのSQLは、VB的にはただの文字列です。s &= "Select 見積ID,顧客名,sum(見積詳細.金額) "
s &= " From 見積 Join 顧客 on 見積.顧客ID=顧客.顧客ID Join 見積詳細 on 見積.見積ID=見積詳細.見積ID "
s &= " Where 見積ID>=100 and 見積詳細.金額>=0"
s &= " Group By 見積ID,顧客名 "
s &= " Having sum(見積詳細.金額)>=100"
Debug.Print(s)
これではいけません。ただの文字列ではなく、意味を持たせましょう。
そのために次のようなクラスを作成しました。
Class SQL
Dim s As String = ""
Public Sub New()
End Sub
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Function [Select](ByVal ParamArray arg() As String) As SQL
Me.s &= " Select " & String.Join(",", arg)
Return Me
End Function
Public Function From(ByVal arg As String) As SQL
Me.s &= " From " & arg
Return Me
End Function
Public Shared Widening Operator CType(ByVal a As SQL) As String
Return a.s
End Operator
End Class
Select句とFrom句をSQLオブジェクトの関数にしたので、Dim s As String = ""
Public Sub New()
End Sub
Public Sub New(ByVal s As String)
Me.s = s
End Sub
Public Function [Select](ByVal ParamArray arg() As String) As SQL
Me.s &= " Select " & String.Join(",", arg)
Return Me
End Function
Public Function From(ByVal arg As String) As SQL
Me.s &= " From " & arg
Return Me
End Function
Public Shared Widening Operator CType(ByVal a As SQL) As String
Return a.s
End Operator
End Class
Dim s As String = ""
s &= "Select * "
s &= " From 見積"
Debug.Print(s)
はs &= "Select * "
s &= " From 見積"
Debug.Print(s)
Dim q as New SQL
q.Select("*")
q.From("見積")
Debug.Print(q)
と書けます。どうです?これだけ見るとよさそうでしょ。q.Select("*")
q.From("見積")
Debug.Print(q)
足りないSQL句を実装して最初の例を記述すると次のようになりました。
(SQLクラスの全ソースは次回に記載します。)
Dim q as New SQL
q.Select("見積ID", "顧客名", "sum(見積詳細.金額)")
q.From("見積")
q.Join("顧客", "見積.顧客ID=顧客.顧客ID")
q.Join("見積詳細", "見積.見積ID=見積詳細.見積ID")
q.Where("見積ID>=100 and 見積詳細.金額>=0")
q.GroupBy("見積ID", "顧客名")
q.Having("sum(見積詳細.金額)>=100")
Debug.Print(q)
q.Select("見積ID", "顧客名", "sum(見積詳細.金額)")
q.From("見積")
q.Join("顧客", "見積.顧客ID=顧客.顧客ID")
q.Join("見積詳細", "見積.見積ID=見積詳細.見積ID")
q.Where("見積ID>=100 and 見積詳細.金額>=0")
q.GroupBy("見積ID", "顧客名")
q.Having("sum(見積詳細.金額)>=100")
Debug.Print(q)
行を分けずに書けばこんな感じです(うげ~)
Dim q as New SQL
q.Select("見積ID", "顧客名", "sum(見積詳細.金額)").From("見積").Join("顧客", "見積.顧客ID=顧客.顧客ID").Join("見積詳細", "見積.見積ID=見積詳細.見積ID").Where("見積ID>=100 and 見積詳細.金額>=0").GroupBy("見積ID", "顧客名").Having("sum(見積詳細.金額)>=100")
Debug.Print(q)
q.Select("見積ID", "顧客名", "sum(見積詳細.金額)").From("見積").Join("顧客", "見積.顧客ID=顧客.顧客ID").Join("見積詳細", "見積.見積ID=見積詳細.見積ID").Where("見積ID>=100 and 見積詳細.金額>=0").GroupBy("見積ID", "顧客名").Having("sum(見積詳細.金額)>=100")
Debug.Print(q)
次回に続きます。
イイ!と思ったら拍手をお願いします↓
コマンドラインからCD-R/DVD-Rの制御
テーマ:Windows
2009年10月26日 13時33分
コマンドラインからCD-R/DVD-Rの制御
Windows SDK 付属の imapi2sample を使用すると
コマンドラインから DVD-R や CD-R の書き込みが出来るようになります。
今回は、imapi2sample をビルドするのに Visual Studio 2005 を使用しました。
まず、Windows SDK をダウンロードし、インストールします。
「for Windows Vista」となっていますが、Windows XP もサポートOS に含まれています。
Windows SDK for Windows Vista
http://www.microsoft.com/downloads/details.aspx?FamilyID=7614fe22-8a64-4dfb-aa0c-db53035f40a0&DisplayLang=ja
Windows SDK の インストールが完了したら、Visual Studio に統合します。
スタートメニューに「Windows SDK と Visual Studio 2005の統合」が追加されれているので、これを実行します。
imapi2sample が Windows SDK をインストールしたディレクトリの
Samples\WinBase\imapi に有るので、これを適当なディレクトリにコピーし
Visual Studio で開きます。
そのままだと進捗の表示が化けるので、次のように変更しビルドを行います。
(unidiff形式です。)
--- consoleUtil.cpp Thu Jan 15 17:52:48 1970
+++ consoleUtil.cpp Thu Jan 15 17:52:48 1970
@@ -36,20 +36,20 @@
// NOTE: Overflow possibility exists for large numerators.
percent = (Numerator * 100) / Denominator;
// each block is 2%
// ----=----1----=----2----=----3----=----4----=----5----=----6----=----7----=----8
// ア.....................
for (i=1; i<100; i+=2) {
if (i < percent) {
- putchar(178);
+ putchar('#');
} else if (i == percent) {
- putchar(177);
+ putchar('*');
} else {
- putchar(176);
+ putchar('-');
}
}
printf(" %d%%", percent);
}
--- Erase2Event.cpp Thu Jan 15 17:52:48 1970
+++ Erase2Event.cpp Thu Jan 15 17:52:48 1970
@@ -35,27 +35,27 @@
// NOTE: Overflow possibility exists for large numerators.
percent = (Numerator * 100) / Denominator;
// each block is 2%
// ----=----1----=----2----=----3----=----4----=----5----=----6----=----7----=----8
// ア.....................
for (i=1; i<100; i+=2) {
if (i < percent) {
- putchar(178);
+ putchar('#');
} else if (i == percent) {
- putchar(177);
+ putchar('*');
} else {
- putchar(176);
+ putchar('-');
}
}
printf(" %d%%", percent);
}
STDMETHODIMP_(VOID) CTestErase2Event::Update(IDispatch* object, LONG elapsedTime, LONG totalTime)
{
UNREFERENCED_PARAMETER (object);
DeleteCurrentLine2();
UpdatePercentageDisplay2(elapsedTime, totalTime);
imapi2sample を実行するには IMAPIv2 が必要です。
Vista 以降で有れば標準で対応しているようですが、
XP の場合は別途マイクロソフトのサイトからダウンロードする必要があります。
Windows XP 用 Image Mastering API v2.0 (IMAPIv2.0) (KB932716)
http://www.microsoft.com/downloads/details.aspx?FamilyID=B5F726F1-4ACE-455D-BAD7-ABC4DD2F147B&displaylang=ja
以上で imapi2sample の用意が出来ました。
でトレイの開閉が出来ます。
で CD-RW/DVD-RW の消去が出来ます。
でディレクトリを書き込むことが出来ます。
Windows SDK 付属の imapi2sample を使用すると
コマンドラインから DVD-R や CD-R の書き込みが出来るようになります。
今回は、imapi2sample をビルドするのに Visual Studio 2005 を使用しました。
まず、Windows SDK をダウンロードし、インストールします。
「for Windows Vista」となっていますが、Windows XP もサポートOS に含まれています。
Windows SDK for Windows Vista
http://www.microsoft.com/downloads/details.aspx?FamilyID=7614fe22-8a64-4dfb-aa0c-db53035f40a0&DisplayLang=ja
Windows SDK の インストールが完了したら、Visual Studio に統合します。
スタートメニューに「Windows SDK と Visual Studio 2005の統合」が追加されれているので、これを実行します。
imapi2sample が Windows SDK をインストールしたディレクトリの
Samples\WinBase\imapi に有るので、これを適当なディレクトリにコピーし
Visual Studio で開きます。
そのままだと進捗の表示が化けるので、次のように変更しビルドを行います。
(unidiff形式です。)
--- consoleUtil.cpp Thu Jan 15 17:52:48 1970
+++ consoleUtil.cpp Thu Jan 15 17:52:48 1970
@@ -36,20 +36,20 @@
// NOTE: Overflow possibility exists for large numerators.
percent = (Numerator * 100) / Denominator;
// each block is 2%
// ----=----1----=----2----=----3----=----4----=----5----=----6----=----7----=----8
// ア.....................
for (i=1; i<100; i+=2) {
if (i < percent) {
- putchar(178);
+ putchar('#');
} else if (i == percent) {
- putchar(177);
+ putchar('*');
} else {
- putchar(176);
+ putchar('-');
}
}
printf(" %d%%", percent);
}
--- Erase2Event.cpp Thu Jan 15 17:52:48 1970
+++ Erase2Event.cpp Thu Jan 15 17:52:48 1970
@@ -35,27 +35,27 @@
// NOTE: Overflow possibility exists for large numerators.
percent = (Numerator * 100) / Denominator;
// each block is 2%
// ----=----1----=----2----=----3----=----4----=----5----=----6----=----7----=----8
// ア.....................
for (i=1; i<100; i+=2) {
if (i < percent) {
- putchar(178);
+ putchar('#');
} else if (i == percent) {
- putchar(177);
+ putchar('*');
} else {
- putchar(176);
+ putchar('-');
}
}
printf(" %d%%", percent);
}
STDMETHODIMP_(VOID) CTestErase2Event::Update(IDispatch* object, LONG elapsedTime, LONG totalTime)
{
UNREFERENCED_PARAMETER (object);
DeleteCurrentLine2();
UpdatePercentageDisplay2(elapsedTime, totalTime);
imapi2sample を実行するには IMAPIv2 が必要です。
Vista 以降で有れば標準で対応しているようですが、
XP の場合は別途マイクロソフトのサイトからダウンロードする必要があります。
Windows XP 用 Image Mastering API v2.0 (IMAPIv2.0) (KB932716)
http://www.microsoft.com/downloads/details.aspx?FamilyID=B5F726F1-4ACE-455D-BAD7-ABC4DD2F147B&displaylang=ja
以上で imapi2sample の用意が出来ました。
imapi2sample.exe -eject
imapi2sample.exe -inject
imapi2sample.exe -inject
でトレイの開閉が出来ます。
imapi2sample.exe -erase
で CD-RW/DVD-RW の消去が出来ます。
imapi2sample.exe -write ディレクトリ
でディレクトリを書き込むことが出来ます。




