Access (VBA) |
|
(Windows 11全般 : Access 2021)
VBAでテーブルに"複数の値の許可"のフィールドを設定する方法
投稿日時: 25/11/30 10:20:00
投稿者: RIGEL
|
|---|---|
|
DAOでテーブルのもともとのルックアップ設定されていないフィールドをルックアップされる"複数の値の許可"へ設定変更しようとしています。
Dim tc As DAO.TableDef
Dim td As DAO.TableDef
Dim fld As DAO.Field
With CurrentDb
Set td = .TableDefs("ConData")
Set fld = td("Labels")
'◆やってみたこと@
' 元々の何の変哲もないフィールドに対して設定を変更させてみます。
fld.Properties("DisplayControl") = 111
fld.Properties.Append fld.CreateProperty("AllowMultipleValues", dbBoolean, True)
fld.Properties.Append fld.CreateProperty("RowSourceType", dbText, "Table/Query")
fld.Properties.Append fld.CreateProperty("RowSource", dbText, "tbl_Labels")
fld.Properties.Append fld.CreateProperty("LimitToList", dbBoolean, True)
'↑ここまではOK
'↓データ型を変更させられません:以下のセクションを上記の冒頭に持っていってもダメ
fld.Type = 109 ' Error 3219:無効な処理です
fld.Attributes = 1 ' Error 3219:無効な処理です
fld.Properties("Precision") = 3 ' 値が変化しません:そもそもこれは変更しなくてもいいのかな
' ここまでで上記のエラーを無視して進め、テーブルをデータシートビューにしようとテーブル名をダブルクリックすると
'┃複数の値を格納できるように'Labels'ルックアップ列を変更しました。
'┃テーブルを保存した後に、この変更を戻すことが出来ません
'┃!複数の値を格納するように'Labels'を変更してもよろしいですか?
'┃ [はい][いいえ]
' のようなダイアログが表示されます。
' ここで[はい]とすれば目的のテーブルが完成します。
' なので、手動ではなくVBAで
' DoCmd.OpenTable "ConData", acViewNormal
' としてみますが、これでは上記の警告メッセージが表示されませんでした。
'◆やってみたことA
' 別のテーブルに"複数の値の許可"を設定したフィールドをワーク的に作成
' そのフィールドを対象テーブルにAppendしてみようとすると
Set tc = .TableDefs("ComplexFieldOnly")
Set fld = td.CreateField(tc(0))
td.Fields.Append fld ' Error 3259:フィールドの型が正しくありません
End With
なにか順番通りに手順を踏まないとダメ!みたいなものでも存在してるのでしょうか? |
|
|
|
投稿日時: 25/12/01 13:02:39
投稿者: sk
|
|---|---|
引用: 既存のフィールドを「複数の値を持つフィールド」に直接変更する処理を VBA によって実行することは恐らく不可能でしょう。 デザインビューで変更するのが最も確実で手っ取り早いはず。 引用: 引用: 既存のフィールドを参照する Field オブジェクトの Type プロパティは 読み取り専用です。 Type プロパティの設定が可能なのは、まだテーブル定義に追加されていない ( TableDef オブジェクトの CreateField メソッドによって生成された) Field オブジェクトを参照している場合だけです。 従来の( Access 2003 以前からある)データ型に変更する場合は 「データ定義クエリを実行する」という方法が一般的ですが、 Access SQL は「複数の値を持つフィールド」を定義する命令を サポートしていません。 とりあえず考え得る代替策としては、次のようなものぐらいでしょうか。 ---------------------------------------------------------------------- 1. データ型の変更対象となるフィールドを含むテーブル定義を参照する。 2. 上記 1 のテーブル定義に「複数の値を持つフィールド」を 仮の名前(他のフィールドと競合しない名前)で新規作成する (追加する前にそのフィールドの OrdinalPosition プロパティの設定も行なう)。 3. もしそのテーブルに 1 件以上のレコードが格納されている場合は、 データ型の変更対象となるフィールドに格納されているデータを 上記 2 のフィールドのデータに変換する処理を 全てのレコードに対して実行する。 4. データ型の変更対象となるフィールドをテーブル定義から削除する。 5. 上記 2 のフィールドの名前を上記 4 のフィールドと同じ名前に変更する。 ---------------------------------------------------------------------- 一連の処理が途中で終了してしまうと大変困ったことになるでしょうから、 トランザクション制御は必須です。 |
|
|
|
投稿日時: 25/12/01 16:36:02
投稿者: RIGEL
|
|---|---|
|
Propertiesで値を変更するようなダイレクトで制御する方法は無さそうなのですね
|
|
|
|
投稿日時: 25/12/01 17:06:17
投稿者: Suzu
|
|---|---|
|
こんにちは。
|
|
|
|
投稿日時: 25/12/01 17:45:03
投稿者: RIGEL
|
|---|---|
|
一つのデータに対して複数のラベルを付けたいのです。
|
|
|
|
投稿日時: 25/12/01 18:24:36
投稿者: sk
|
|---|---|
|
とりあえずサンプルコードを挙げると次のような感じかと。
Sub AlterFieldTypeToComplex()
On Error GoTo Err_AlterFieldTypeToComplex
Const TargetTableName As String = "ConData"
Const TargetFieldName As String = "Labels"
Const NewRowSource As String = "tbl_Labels"
Dim ws As DAO.Workspace
Set ws = DBEngine.Workspaces(0)
Dim db As DAO.Database
Set db = CurrentDb
Dim tdf As DAO.TableDef
Set tdf = db.TableDefs(TargetTableName)
Dim fldOld As DAO.Field2
Set fldOld = tdf.Fields(TargetFieldName)
Dim intNewDataType As DAO.DataTypeEnum
'元のデータ型に応じて新しいデータ型を決定
Select Case fldOld.Type
'バイト型である場合
Case dbByte
'複数値バイト型に
intNewDataType = dbComplexByte
'10 進型である場合
Case dbDecimal
'複数値 10 進型に
intNewDataType = dbComplexDecimal
'倍精度浮動小数点型である場合
Case dbDouble
'複数値倍精度浮動小数点型に
intNewDataType = dbComplexDouble
'GUID 型(レプリケーション ID型)である場合
Case dbGUID
'複数値 GUID 型に
intNewDataType = dbComplexGUID
'整数型である場合
Case dbInteger
'複数値整数型に
intNewDataType = dbComplexInteger
'長整数型である場合
Case dbLong
'複数値長整数型に
intNewDataType = dbComplexLong
'単精度浮動小数点型である場合
Case dbSingle
'複数値単精度浮動小数点型に
intNewDataType = dbComplexSingle
'テキスト型である場合
Case dbText
'複数値テキスト型に
intNewDataType = dbComplexText
'いずれかの複数値データ型である場合
Case dbComplexByte, dbComplexDecimal, dbComplexDouble, _
dbComplexGUID, dbComplexInteger, dbComplexLong, _
dbComplexSingle, dbComplexText
'エラーメッセージを表示
MsgBox "テーブル定義[" & TargetTableName & "]のフィールド[" & fldOld.Name & "]は複数の値を持つフィールドです。", _
vbExclamation, _
"変更不要のフィールド (AlterFieldTypeToComplex)"
Set fldOld = Nothing
Set tdf = Nothing
Set db = Nothing
Set ws = Nothing
'プロシージャを抜ける
Exit Sub
'上記以外の型である場合
Case Else
'エラーメッセージを表示
MsgBox "テーブル定義[" & TargetTableName & "]のフィールド[" & fldOld.Name & "]の現在のデータ型は複数値をサポートしていません。", _
vbExclamation, _
"データ型変換エラー (AlterFieldTypeToComplex)"
Set fldOld = Nothing
Set tdf = Nothing
Set db = Nothing
Set ws = Nothing
'プロシージャを抜ける
Exit Sub
End Select
'トランザクション処理を開始
ws.BeginTrans
On Error GoTo RollBack_AlterFieldTypeToComplex
'複数の値を持つフィールドを新規作成する
Dim strTempFieldName As String
'仮のフィールド名を設定
strTempFieldName = fldOld.Name & "_New"
Dim fldNew As DAO.Field2
'新規フィールドの生成
Set fldNew = tdf.CreateField(strTempFieldName)
'新しいデータ型(いずれかの複数値データ型)を設定
fldNew.Type = intNewDataType
'属性を複写
fldNew.Attributes = fldOld.Attributes
'テーブル定義上の順番を複写
fldNew.OrdinalPosition = fldOld.OrdinalPosition
'新規フィールドをテーブル定義に追加
tdf.Fields.Append fldNew
tdf.Fields.Refresh
Set fldNew = Nothing
'追加後のフィールドを参照
Set fldNew = tdf.Fields(strTempFieldName)
'ユーザー定義プロパティの設定例(実際はもっと色々やった方が良いが、とりあえずルックアップ周りのみ)
With fldNew.Properties
.Append fldNew.CreateProperty("AllowMultipleValues", dbBoolean, True)
.Append fldNew.CreateProperty("DisplayControl", dbInteger, acComboBox)
.Append fldNew.CreateProperty("RowSourceType", dbText, "Table/Query")
If NewRowSource <> "" Then
.Append fldNew.CreateProperty("RowSource", dbMemo, NewRowSource)
End If
.Append fldNew.CreateProperty("BoundColumn", dbInteger, 1)
.Append fldNew.CreateProperty("ColumnCount", dbInteger, 1)
.Append fldNew.CreateProperty("ColumnHeads", dbBoolean, False)
.Append fldNew.CreateProperty("ListRows", dbInteger, 16)
.Append fldNew.CreateProperty("ListWidth", dbText, "0twip")
.Append fldNew.CreateProperty("LimitToList", dbBoolean, False)
.Append fldNew.CreateProperty("AllowValueListEdits", dbBoolean, False)
.Append fldNew.CreateProperty("ShowOnlyRowSourceValues", dbBoolean, False)
.Refresh
End With
'フィールドおよびテーブル定義への参照を解放
Set fldNew = Nothing
Set fldOld = Nothing
Set tdf = Nothing
'格納済みのレコードのデータ変換処理
Dim rsTarget As DAO.Recordset2
Dim rsComplex As DAO.Recordset2
'変換対象となるフィールドを含むテーブルのレコードセットを開く
Set rsTarget = db.OpenRecordset(TargetTableName, dbOpenDynaset)
'全てのレコードを読み切るまでループ
Do Until rsTarget.EOF
Set fldOld = rsTarget.Fields(TargetFieldName)
Set fldNew = rsTarget.Fields(strTempFieldName)
'変換元のフィールドの値が Null ではない場合
If Not IsNull(fldOld.Value) Then
'カレントレコードの編集を開始
rsTarget.Edit
'変換先が複数値フィールドである場合
If fldNew.IsComplex Then
'複数値フィールドのレコードセットを参照する
Set rsComplex = fldNew.Value
'そのレコードセットに新規レコードを追加し、変換元のフィールドの値を代入して保存
rsComplex.AddNew
rsComplex.Fields("Value") = fldOld.Value
rsComplex.Update
'そのレコードセットへの参照を解放
Set rsComplex = Nothing
'変換先が複数値フィールドではない場合
Else
'変換元のフィールドの値をそのまま代入
fldNew.Value = fldOld.Value
End If
'カレントレコードを保存
rsTarget.Update
End If
Set fldNew = Nothing
Set fldOld = Nothing
'次のレコードを移動
rsTarget.MoveNext
Loop
'レコードセットへの参照を解放
Set rsTarget = Nothing
'新旧フィールドの入れ替え
'テーブル定義を再参照
Set tdf = db.TableDefs(TargetTableName)
'元のフィールドを削除する
tdf.Fields.Delete TargetFieldName
'新しく追加したフィールドの名前を元のフィールドと同じ名前にリネームする
tdf.Fields(strTempFieldName).Name = TargetFieldName
'コミット(全ての変更を有効にしてトランザクション処理を終了)
ws.CommitTrans
On Error GoTo Err_AlterFieldTypeToComplex
'成功時のメッセージ表示
MsgBox "テーブル定義[" & TargetTableName & "]のフィールド[" & TargetFieldName & "]を複数の値を持つフィールドに変更しました。", _
vbInformation, _
"実行完了 (AlterFieldTypeToComplex)"
'終了処理
Exit_AlterFieldTypeToComplex:
On Error Resume Next
Set fldNew = Nothing
Set fldOld = Nothing
Set rsComplex = Nothing
Set rsTarget = Nothing
Set tdf = Nothing
Set db = Nothing
Set ws = Nothing
'プロシージャを抜ける
Exit Sub
'トランザクション実行中はここからエラー時処理
RollBack_AlterFieldTypeToComplex:
'ロールバック(全ての変更を取り消してトランザクション処理を終了)
ws.Rollback
'エラー時処理
Err_AlterFieldTypeToComplex:
Dim ErrMsg As String
ErrMsg = Err.Number & ": " & Err.Description
Debug.Print ErrMsg
'エラーメッセージの表示
MsgBox ErrMsg, vbCritical, "実行時エラー(AlterFieldTypeToComplex)"
'終了処理へ
Resume Exit_AlterFieldTypeToComplex
End Sub------------------------------------------------------------------------ |
|
|
|
投稿日時: 25/12/02 08:15:14
投稿者: RIGEL
|
|---|---|
|
わざわざコード提示ありがとうございます。
|
|



