VERSION 1.0 CLASS
BEGIN
MultiUse = -1 'True
END
Attribute VB_Name = "textSQL"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit
Private working_dir As String
Public Enum readtype
RowHead = 0
Number = 1
End Enum
Public Enum SortOrder
orderASC = 0
orderDESC = 1
End Enum
Public Enum SepKey
keyComma = 1
keyTab
End Enum
Public Function runif(ByVal get_number As Long, ByVal nmin As Long, ByVal nmax As Long) As Variant
'' ランダム数値の作成
'' get_number: 取得する数値の数
'' nmin: 最小値
'' nmax: 最大値
Dim n As Long
Dim dic As Object
'' ランダム値の生成
Set dic = Set_Dictionary
'' シードの初期化
Randomize
'' 日付_時間_ランダム数値として作成
Do While dic.Count <> get_number
n = Int((nmax - nmin + 1) * Rnd + nmin)
If dic.exists(n) = False Then
dic.Add n, Format(Now(), "yyyyMMdd_HHmmSS_") & Format(n, "00000")
End If
Loop
runif = dic.items
End Function
Public Function CREATE_DataBase()
Call Set_New_Data_Base
End Function
Public Function CREATE_DataTable(ByVal create_table_name As String, ByVal table_column_types As Variant, _
ByVal table_column_names As Variant)
Call SQL("CREATE", "TABLE", create_table_name, table_column_types, table_column_names)
End Function
Public Function INSERT_Columns(ByVal table_name As String, ByVal table_column_types As Variant, _
ByVal table_column_names As Variant, ByVal set_insert_columns_number As Long) As Object
'' INSERT table名 データ型配列、データ名配列、挿入位置の数字
' Set INSERT_Columns = Insert_New_Column_To_DataTable(table_name, set_insert_columns_number, _
' table_column_types, table_column_names)
Call SQL("INSERT", table_name, table_column_types, table_column_names, set_insert_columns_number)
End Function
Public Function UPDATE_Table(ByVal table_name As String, ByVal update_data As Variant)
'' UPDATE table名 dictionary名|配列名
Call SQL("UPDATE", table_name, update_data)
End Function
Public Function DELETE_Items(ByVal table_name As String, ByVal delete_key As Variant)
'' DELETE table名 *
'' DELETE table名 削除データキー配列
Call SQL("DELETE", table_name, delete_key)
End Function
Public Function DROP_Table(ByVal table_name As String)
Call SQL("DROP", table_name)
End Function
Public Function tables() As Variant
tables = Get_Table_List
End Function
Public Function table_ColNames(ByVal table_name As String) As Variant
Dim dic As Object
Set dic = Read_DataTable(table_name)
table_ColNames = dic.item("name")
End Function
Public Function table_Count(ByVal table_name As String) As Variant
Dim dic As Object
Set dic = Read_DataTable(table_name)
table_Count = dic.Count - 3
End Function
Public Function SELECT_Table(ByVal table_name As String, _
Optional view_column_names As Variant = "*", _
Optional select_column_names As Boolean = False, _
Optional formula As String = "", _
Optional order_table As Boolean = False, _
Optional names_to_order As String = "", _
Optional ASC_or_DESC As SortOrder = SortOrder.orderASC, _
Optional table_join As Boolean = False, _
Optional join_key_name As String = "", _
Optional join_table_name As String = "") As Object
'' SELECT * table名 WHERE 条件式
'' SELECT 列名配列 table名 ORDER 列名 ASC|DESC
'' SELECT 列名配列 table名 JOIN 列名 table名
Dim connection As Variant
'' 条件式による分岐
connection = Array(select_column_names, order_table, table_join)
Select Case join(connection, ",")
Case join(Array(False, False, False), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name)
Case join(Array(True, False, False), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name, _
"WHERE", formula)
Case join(Array(False, True, False), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name, _
"ORDER", names_to_order, ASC_or_DESC)
Case join(Array(False, False, True), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name, _
"JOIN", join_key_name, join_table_name)
Case join(Array(True, True, False), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name, _
"WHERE", formula, _
"ORDER", names_to_order, ASC_or_DESC)
Case join(Array(True, False, True), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name, _
"WHERE", formula, _
"JOIN", join_key_name, join_table_name)
Case join(Array(False, True, True), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name, _
"ORDER", names_to_order, ASC_or_DESC, _
"JOIN", join_key_name, join_table_name)
Case join(Array(True, True, True), ",")
Set SELECT_Table = SQL("SELECT", view_column_names, table_name, _
"WHERE", formula, _
"ORDER", names_to_order, ASC_or_DESC, _
"JOIN", join_key_name, join_table_name)
End Select
End Function
Public Function arr2dic(ByVal table_array As Variant) As Variant
Dim dt() As Variant
Dim stext As String
Dim i, j As Long
If InStr("文字列,数値,日付,時間", table_array(LBound(table_array, 1), LBound(table_array, 2))) > 0 Then
ReDim dt(LBound(table_array, 1) To UBound(table_array, 1) - 1, _
LBound(table_array, 2) To UBound(table_array, 2))
For i = LBound(table_array, 1) + 1 To UBound(table_array, 1)
For j = LBound(dt, 2) To UBound(dt, 2)
dt(i - 1, j) = table_array(i, j)
Next
Next
End If
Set table_array = Array_to_Dictionary(dt, 1)
End Function
Public Function dic2arr(ByVal table_object As Object) As Variant
dic2arr = Dictionary_to_Array(table_object)
End Function
Public Function SQL(ParamArray sql_code()) '' saaa
'' SQL構文を使って操作
Dim scode As String
Dim dic As Object
Dim i As Long
Dim ikey As Variant
Dim filename As String
Dim ch As String
Select Case sql_code(0)
Case "CREATE"
'' CREATE DATATABLE
'' CREATE TABLE table名 データ型配列 データ列名配列
'' 文字列変換
If sql_code(1) = "DATABASE" Then
Call Set_New_Data_Base
ElseIf sql_code(1) = "TABLE" Then
Call Add_Data_Table(sql_code(2), 1, sql_code(3), sql_code(4))
MsgBox sql_code(2) & "を作成しました", vbInformation
Else
MsgBox "書き方が間違っています。"
Exit Function
End If
Case "SELECT"
'' SELECT * table名 WHERE 条件式
'' SELECT 列名配列 table名 ORDER 列名 ASC|DESC
'' SELECT 列名配列 table名 JOIN 列名 table名
If Search_Dimentions(sql_code(1)) = 1 Then
Set dic = Select_Columns(Read_DataTable(sql_code(2)), sql_code(1))
ElseIf sql_code(1) = "*" Then
Set dic = Read_DataTable(sql_code(2))
Else
MsgBox "構文が間違ってきます。"
Exit Function
End If
If UBound(sql_code) < 3 Then GoTo Continue_Select
For i = 3 To UBound(sql_code)
Select Case sql_code(i)
Case "WHERE"
Set dic = SELECT_MODE(dic, sql_code(i), sql_code(i + 1))
i = i + 1
Case "ORDER", "JOIN"
Set dic = SELECT_MODE(dic, sql_code(i), sql_code(i + 1), sql_code(i + 2))
i = i + 2
End Select
Next
Continue_Select:
Set SQL = dic
Case "INSERT"
'' INSERT table名 データ型配列、データ名配列、挿入位置の数字
Set SQL = Insert_New_Column_To_DataTable(sql_code(1), sql_code(4), sql_code(2), sql_code(3))
Call Make_Backup_File(sql_code(1))
Case "UPDATE"
'' UPDATE table名 dictionary名|配列名
Call Write_DataTable(sql_code(1), Update_DataTable(sql_code(1), sql_code(2)))
Call Make_Backup_File(sql_code(1))
Case "DELETE"
'' DELETE table名 *
'' DELETE table名 削除データキー配列
Set dic = Read_DataTable(sql_code(1))
If sql_code(2) = "*" Then
For Each ikey In dic
If ikey = "primary_key" Or ikey = "name" Or ikey = "type" Then
Else
dic.Remove ikey
End If
Next
Else
If Search_Dimentions(sql_code(2)) = 0 Then sql_code(2) = Array(sql_code(2))
For Each ikey In sql_code(2)
dic.Remove ikey
Next
End If
''Set SQL = dic
Call Write_DataTable(sql_code(1), dic)
Call Make_Backup_File(sql_code(1))
Case "DROP"
'' DROP table名
filename = DT_name(sql_code(1))
ch = MsgBox(filename & vbCrLf & "このテーブルを削除しますか?", vbYesNo)
If ch = 6 Then
Kill filename
Debug.Print "Remove File: " & filename
MsgBox filename & vbCrLf & "テーブルを削除しました。", vbInformation
End If
Case ".table"
'' .table
SQL = Get_Table_List
Case ".table.names"
Set dic = Read_DataTable(sql_code(1))
SQL = dic.item("name")
End Select
End Function
Private Function SELECT_MODE(ByVal dic As Object, ByVal mode As Variant, ParamArray p()) As Object
On Error GoTo Continue
Dim num As Long
Select Case mode
Case "WHERE"
Set SELECT_MODE = Filter_Data_Table(dic, p(0))
Case "ORDER"
' If InStr(p(1), "ASC") > 0 Then
' num = 0
' ElseIf InStr(p(1), "DESC") > 0 Then
' num = 1
' Else
' num = 0
' End If
'
' Set SELECT_MODE = Sort_Data_Table(dic, p(0), num)
Set SELECT_MODE = Sort_Data_Table(dic, p(0), p(1))
Case "JOIN"
Set SELECT_MODE = Left_Join(dic, p(0), Read_DataTable(p(1)))
Case Else
Set SELECT_MODE = dic
End Select
Continue:
End Function
Private Sub Make_Backup_File(ByVal DataTable_name As String)
'' バックアップファイルを作成
Dim bf As String
bf = Join_Path(working_dir, "Backups\" & Format(Now(), "yyyyMMdd_HHmmSS") & "_backup_file_" & DataTable_name & ".txt")
FileCopy DT_name(DataTable_name), bf
End Sub
Private Function Remove_Rows_From_2dimArray(ByVal dt As Variant, ByVal row_num As Long) As Variant
'' 2次元配列の対象列を除外
'' row_num: 除外する行番号
Dim New_dt() As Variant
Dim i, j As Long
ReDim New_dt(LBound(dt, 1) To UBound(dt, 1) - 1, LBound(dt, 2) To UBound(dt, 2))
For i = LBound(dt, 1) To UBound(dt, 1)
For j = LBound(dt, 2) To UBound(dt, 2)
If i < row_num Then
New_dt(i, j) = dt(i, j)
ElseIf i > row_num Then
New_dt(i - 1, j) = dt(i, j)
End If
Next
Next
Remove_Rows_From_2dimArray = New_dt
End Function
Public Function arr2DicArr(ByVal data_array As Variant) As Variant
arr2DicArr = Get_Table_To_Array(data_array)
End Function
Private Function Get_Table_To_Array(ByVal dt As Variant) As Variant
'' 二次元配列を列名でdictionaryに登録し、それを配列にする
'' Update_DataTableのインプットデータに使用
'' dt: 2次元配列
'' 最初の行は列名にする
'' | 列名 | 列名 | 列名...|
'' | 値 | 値 | 値... |
Dim New_data() As Variant
Dim col_name() As Variant
Dim i, j, num As Long
Dim bCell As Variant
ReDim New_data(LBound(dt, 1) To UBound(dt, 1) - 1)
ReDim col_name(LBound(dt, 2) To UBound(dt, 2)) As Variant
'' 列名取得
For i = LBound(dt, 2) To UBound(dt, 2)
col_name(i) = dt(LBound(dt, 1), i)
Next
'' データを登録
For i = LBound(dt, 1) To UBound(dt, 1) - 1
Set New_data(i) = Set_Dictionary
For j = LBound(col_name) To UBound(col_name)
New_data(i).Add col_name(j), dt(i + 1, j)
Next
Next
Get_Table_To_Array = New_data
End Function
Private Function Get_DataTable_Format(ByVal DataTable_name As String) As Object
'' データテーブルに登録するために、空のdictionaryを取得
Dim n As Integer
Dim i As LongPtr
Dim text As String
Dim dic As Object
Set dic = Set_Dictionary
n = FreeFile
Open DT_name(DataTable_name) For Input As #n
i = 1
Do While Not EOF(n)
Line Input #n, text
If text = "" Then GoTo Continue
If i = 3 Then
For Each ikey In Split(text, vbTab)
dic.Add ikey, ""
Next
dic.Remove ("NAME")
End If
Continue:
i = i + 1
Loop
Close #n
Set Get_DataTable_Format = dic
End Function
Public Function filter4dic(ByVal data_object As Object, ByVal formula As String) As Object
Set filter4dic = Filter_Data_Table(data_object, formula)
End Function
Private Function Filter_Data_Table(ByVal data As Object, ByVal formula As String) As Object
'' Dictionaryタイプで取り込んだall_dataをフィルター処理
Dim d_Type, d_name As Variant
Dim fs As Variant
Dim i As Long
Dim ops As Variant
Dim base_data, f_data, or_data As Object
Dim sval, tval, ikey As Variant
''d_Type = data.item("type")
d_name = data.item("name")
'' 式と条件を分割
fs = Separate_Formula(formula)
'' 分岐前のコピーを作成
Set base_data = data
i = 1
Do
'' 比較演算子の判定
ops = Select_Operator(fs(1)(i), d_name)
'' 検索
Set f_data = Set_Dictionary
'' データ型の取得
If ops(0) <> "NA" Then
d_Type = data.item("type")(ops(1))
Else
d_Type = "文字列"
End If
'' 検索条件値のフォーマット変換
sval = Text_Format(ops(2), d_Type)
If IsEmpty(sval) Then
GoTo Continue
End If
For Each ikey In base_data.keys
'' 列名とデータ型は必ず登録
If ikey = "primary_key" Or ikey = "name" Or ikey = "type" Then
f_data.Add ikey, base_data(ikey)
GoTo Continue
End If
'' 対象データを取得
If ops(0) <> "NA" Then
tval = Text_Format(base_data(ikey)(ops(1)), d_Type)
Else
tval = join(base_data(ikey), ",")
End If
If IsEmpty(tval) Then GoTo Continue
'' 該当するデータを登録
Select Case ops(0)
Case "="
If InStr(tval, sval) > 0 Then
f_data.Add ikey, base_data(ikey)
End If
Case "=="
If tval = sval Then
f_data.Add ikey, base_data(ikey)
End If
Case "!="
If tval <> sval Then
f_data.Add ikey, base_data(ikey)
End If
Case ">=", "=>"
If tval >= sval Then
f_data.Add ikey, base_data(ikey)
End If
Case ">"
If tval > sval Then
f_data.Add ikey, base_data(ikey)
End If
Case "<=", "=<"
If tval <= sval Then
f_data.Add ikey, base_data(ikey)
End If
Case "<"
If tval < sval Then
f_data.Add ikey, base_data(ikey)
End If
Case "NA"
If InStr(tval, sval) > 0 Then
f_data.Add ikey, base_data(ikey)
End If
Case "Error"
Exit For
End Select
Continue:
Next
'' 前回条件がorの場合の処理
If i > 1 Then
If fs(0)(i - 1) = "or" Then
'' or_data(前回検索したデータ)をf_data(今回検索したデータ)に統合
For Each ikey In or_data.keys
If f_data.exists(ikey) = False Then
f_data.Add ikey, or_data(ikey)
End If
Next
End If
End If
'' 今回条件に対する処理
Select Case fs(0)(i)
Case "end"
Exit Do
Case "and"
Set base_data = Nothing
Set base_data = f_data
Set f_data = Nothing
Case "or"
Set or_data = Nothing
Set or_data = f_data
Set f_data = Nothing
End Select
i = i + 1
Loop
Set Filter_Data_Table = f_data
End Function
'''''''''''''''''''''
Private Function Select_Operator(ByVal formula As String, ByVal names As Variant) As Variant
'' 比較演算子の判定 names 配列型の名前リスト
'' ==: 完全一致
'' = : 部分一致
'' !=: 否定
'' > : 大なり
'' >=: 以上
'' < : 小なり
'' <=: 以下
'''''''''''''''''''''