C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

dataviewのRowFilterでの日付変換

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■100669 / inTopicNo.1)  dataviewのRowFilterでの日付変換
  
□投稿者/ ぽん (1回)-(2022/10/12(Wed) 11:30:36)

分類:[.NET 全般] 

2022/10/12(Wed) 11:41:00 編集(投稿者)
2022/10/12(Wed) 11:39:49 編集(投稿者)

コンソールアプリを以下の環境で開発しています

開発環境 Visual Studio 2017
言語   VB.NET


datatableから条件を指定してdataviewで抽出したいのですが、
抽出条件のdatatableの列(=col1)に日付がYYYYMMDD形式の文字型で入っているとして、
RowFilter内でどう日付変換していいのかわかりません。

Using dv As New DataView(dt1,"CDate(Format(col1,'@@@@\/@@\/@@')<= CDate(Format(col2,'@@@@\/@@\/@@')","",DataViewRowState.CurrentRows)

このように書くとエラーになりました。
「式に定義されていない関数呼び出し CDate() が含まれています」と出ました。

知っていらっしゃる方がいらっしゃいましたら、
ご回答 宜しくお願いいたします。
引用返信 編集キー/
■100670 / inTopicNo.2)  Re[1]: dataviewのRowStateでの日付変換
□投稿者/ 魔界の仮面弁士 (3465回)-(2022/10/12(Wed) 11:45:25)
No100669 (ぽん さん) に返信
> datatableから条件を指定してdataviewで抽出したいのですが、
> 抽出条件のdatatableの列(=col1)に日付がYYYYMMDD形式の文字型で入っているとして、

col1, col2 という名前の変数が存在していて、それを使って判定するのではなく、
DataTable に "col1", "col2" という名前の列があって、その大小を比較するという状況で良いですか?


データ型などの細かい話が分からないので推察しかできませんが、
双方の列が「YYYYMMDD 形式の文字列」というのであれば、
それは `固定長` の文字列でしょうから、日付型への変換を気にする必要はないのでは?


Dim dt1 As New DataTable("ぽん")
dt1.Columns.Add("ID", GetType(Integer)).AllowDBNull = False
dt1.Columns.Add("col1", GetType(String))
dt1.Columns.Add("col2", GetType(String))
dt1.PrimaryKey = New DataColumn() {dt1.Columns("ID")}


dt1.Rows.Add(1000, "20210101", "20211231")
dt1.Rows.Add(1010, "20220101", "20220930")
dt1.Rows.Add(1020, "20220101", "20200930")

dt1.AcceptChanges()

' 1000 と 1010 は拾えるが、1020 は除外される
Dim dv As New DataView(dt1) With {.RowFilter = "[col1]<=[col2]"}
引用返信 編集キー/
■100671 / inTopicNo.3)  Re[2]: dataviewのRowStateでの日付変換
□投稿者/ ぽん (2回)-(2022/10/12(Wed) 11:54:29)
No100670 (魔界の仮面弁士 さん) に返信
回答ありがとうございます。
> ■No100669 (ぽん さん) に返信
>>datatableから条件を指定してdataviewで抽出したいのですが、
>>抽出条件のdatatableの列(=col1)に日付がYYYYMMDD形式の文字型で入っているとして、
>
> col1, col2 という名前の変数が存在していて、それを使って判定するのではなく、
> DataTable に "col1", "col2" という名前の列があって、その大小を比較するという状況で良いですか?
>
そうです。

>データ型などの細かい話が分からないので推察しかできませんが、
>双方の列が「YYYYMMDD 形式の文字列」というのであれば、
>それは `固定長` の文字列でしょうから、日付型への変換を気にする必要はないのでは?
双方の列は「YYYYMMDD 形式の文字列」です。
実際にやりたいことはCol1の一か月前と比較したいので、一度日付型に変換したものをDateAddで一か月前の日付に変換したいのですが、
どうすればいいでしょうか?
引用返信 編集キー/
■100672 / inTopicNo.4)  Re[1]: dataviewのRowFilterでの日付変換
□投稿者/ 魔界の仮面弁士 (3466回)-(2022/10/12(Wed) 12:08:35)
No100669 (ぽん さん) に返信
> Using dv As New DataView(dt1,"CDate(Format(col1,'@@@@\/@@\/@@')<= CDate(Format(col2,'@@@@\/@@\/@@')","",DataViewRowState.CurrentRows)
> このように書くとエラーになりました。
> 「式に定義されていない関数呼び出し CDate() が含まれています」と出ました。

CDate という関数は定義されていません。
https://learn.microsoft.com/en-us/dotnet/api/system.data.datacolumn.expression?view=netframework-4.8


col1 が「日付として認識可能な文字列」ではなく、yyyyMMdd 形式の固定長文字列の場合は、
"MM/dd/yyyy" あるいは "yyyy/MM/dd" 形式の文字列として整形する必要があります。
今回のケースで言うと、こうなりますね。

.RowFilter = "CONVERT(SUBSTRING([col1],5,2) +'/' + SUBSTRING([col1],7,2) + '/' + SUBSTRING([col1],1,4), System.DateTime) <= CONVERT(SUBSTRING([col2],5,2) +'/' + SUBSTRING([col2],7,2) + '/' + SUBSTRING([col2],1,4), System.DateTime)"


文字列を強制的に変換する場合は、「CONVERT( 〜〜 , System.DateTime )」という記述を使います。
また、日付型と文字列型を比較するような場合、文字列から日付型への変換は強制的に行われます。

ただしいずれの場合も書式指定子は無いので、"@@@@\/@@\/\@@" のような指定はできません。
なお、日付リテラルを埋め込む場合は 「#M/D/YYYY#」のようにシャープで囲った記法が採用されています。

 .RowFilter = "CONVERT([col1], System.DateTime)>=#10/31/2021#"
引用返信 編集キー/
■100673 / inTopicNo.5)  Re[3]: dataviewのRowStateでの日付変換
□投稿者/ 魔界の仮面弁士 (3467回)-(2022/10/12(Wed) 12:17:13)
No100671 (ぽん さん) に返信
> 一度日付型に変換したものをDateAddで一か月前の日付に変換したいのですが、
DateAdd に相当するものはありません。
ところで、ここでいう「一ヶ月」はどういう定義付けになりますか?


30日後、とかであれば TimeSpan 値を日付値に加算すれば済みますが
閏年や末日判定なども考慮が必要な要件だと、式列仕様では煩雑なので、
DataView ではなく LINQ で抽出したほうが融通が利くでしょう。
引用返信 編集キー/
■100674 / inTopicNo.6)  Re[4]: dataviewのRowStateでの日付変換
□投稿者/ 魔界の仮面弁士 (3468回)-(2022/10/12(Wed) 13:56:24)
2022/10/12(Wed) 14:27:19 編集(投稿者)

No100673 (魔界の仮面弁士) に追記
> ここでいう「一ヶ月」はどういう定義付けになりますか?
> 30日後、とかであれば TimeSpan 値を日付値に加算すれば済みますが
> 閏年や末日判定なども考慮が必要な要件だと、式列仕様では煩雑なので、
> DataView ではなく LINQ で抽出したほうが融通が利くでしょう。


ということで、『(col1 の一ヶ月前) ≦ (col2)』なレコードを
LINQ を使って、DataView として抽出してみました。

「一ヶ月前」の算出を .AddMonths(-1R) で行っているため、
 col2 <= 20221028 の行が取得される条件は、 col1 <= 20221129 の時
 col2 <= 20221029 の行が取得される条件は、 col1 <= 20221130 の時
 col2 <= 20221030 の行が取得される条件は、 col1 <= 20221130 の時
 col2 <= 20221031 の行が取得される条件は、 col1 <= 20221130 の時
 col2 <= 20221201 の行が取得される条件は、 col1 <= 20221201 の時
という結果になります。末日判定などが期待と異なる場合は、適宜調整してみてください。


Dim dt1 As New DataTable("ぽん")
dt1.Columns.Add("ID", GetType(Integer)).AllowDBNull = False
dt1.Columns.Add("col1", GetType(String))
dt1.Columns.Add("col2", GetType(String))
dt1.PrimaryKey = New DataColumn() {dt1.Columns("ID")}

dt1.Rows.Add(2110, "20221129", "20221028") '× 除外
dt1.Rows.Add(2120, "20221129", "20221029") '◎
dt1.Rows.Add(2130, "20221129", "20221030") '◎
dt1.Rows.Add(2140, "20221129", "20221031") '◎
dt1.Rows.Add(2150, "20221129", "20221101") '◎
dt1.Rows.Add(2160, "20221129", "20221102") '◎

dt1.Rows.Add(2210, "20221130", "20221028") '× 除外
dt1.Rows.Add(2220, "20221130", "20221029") '× 除外
dt1.Rows.Add(2230, "20221130", "20221030") '◎
dt1.Rows.Add(2240, "20221130", "20221031") '◎
dt1.Rows.Add(2250, "20221130", "20221101") '◎
dt1.Rows.Add(2260, "20221130", "20221102") '◎

dt1.Rows.Add(2310, "20221201", "20221028") '× 除外
dt1.Rows.Add(2320, "20221201", "20221029") '× 除外
dt1.Rows.Add(2330, "20221201", "20221030") '× 除外
dt1.Rows.Add(2340, "20221201", "20221031") '× 除外
dt1.Rows.Add(2350, "20221201", "20221101") '◎
dt1.Rows.Add(2360, "20221201", "20221102") '◎

dt1.AcceptChanges()

Dim c = System.Globalization.CultureInfo.InvariantCulture
Dim s = System.Globalization.DateTimeStyles.None
Dim ToDate As Func(Of DataRow, String, Date?) =
  Function(row, colName)
    Dim d As Date
    Return If(Date.TryParseExact(row.Field(Of String)(colName), "yyyyMMdd", c, s, d), d, New Date?())
  End Function

Dim dv As DataView = dt1.AsEnumerable().Where(Function(r) If(ToDate(r, "col1")?.AddMonths(-1.0R) <= ToDate(r, "col2"), False)).AsDataView()
引用返信 編集キー/
■100675 / inTopicNo.7)  Re[1]: dataviewのRowFilterでの日付変換
□投稿者/ 大谷刑部 (214回)-(2022/10/12(Wed) 14:26:07)
No100669 (ぽん さん) に返信
> 2022/10/12(Wed) 11:41:00 編集(投稿者)
> 2022/10/12(Wed) 11:39:49 編集(投稿者)
>
> コンソールアプリを以下の環境で開発しています
>
> 開発環境 Visual Studio 2017
> 言語   VB.NET

datatableの元になってるデータソースは何ですか?
DBからSQLで抽出しているのなら、SQLの時点でwhere句でフィルタをかけてしまうか、
あるいは「一か月前」を別項目として取得してしまえば、フィルタに設定するのが関数を介さない単純な条件になるので、
DataviewのRowFilterプロパティーに対応してる関数か否かに悩まされなくて済むはずです。

> datatableから条件を指定してdataviewで抽出したいのですが、
> 抽出条件のdatatableの列(=col1)に日付がYYYYMMDD形式の文字型で入っているとして、
> RowFilter内でどう日付変換していいのかわかりません。
>
> Using dv As New DataView(dt1,"CDate(Format(col1,'@@@@\/@@\/@@')<= CDate(Format(col2,'@@@@\/@@\/@@')","",DataViewRowState.CurrentRows)
>
> このように書くとエラーになりました。
> 「式に定義されていない関数呼び出し CDate() が含まれています」と出ました。

弁さんも指摘なさってますが、CDate関数がRowFilterプロパティーで使えないだけ、というよりは、そもそもVBで使える関数=RowFilterプロパティーで使える関数ではないからです。


引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ