|
受注DBには、列見出しが有る物とします
抽出Keyの位置は、rngListを基準とした列Offsetとします
例えば、A1(列見出し「商品分類」)を基準とすると、A列は0、B列は1、C列は2
実行時に抽出Keyで整列され終了直前に元の行位置に再整列されます
Option Explicit
Public Sub Sample()
'結果出力の先頭位置
Const cstrTop As String = "A1"
Dim i As Long
Dim lngRows As Long
Dim lngColumns As Long
Dim lngTop As Long
Dim lngCount As Long
Dim rngList As Range
Dim rngResult As Range
Dim rngHeader As Range
Dim vntGroup As Variant
Dim vntKeys As Variant
Dim vntColumnWidth As Variant
Dim strProm As String
'Listの先頭セル位置(左上隅)を基準とする(列見出し「商品分類」のセル位置)
Set rngList = Worksheets("受注DB").Cells(1, "A")
'抽出Keyの有る列を指定(rngListで指定した列を基準とした列Offset値)
strProm = "抽出Keyの有る列を指定して下さい(基準位置からの列Offset値)"
vntKeys = Application.InputBox(strProm, , 0, , , , 1)
If VarType(vntKeys) = vbBoolean Then
strProm = "マクロがキャンセルされました"
GoTo Wayout
End If
'画面更新を停止
Application.ScreenUpdating = False
With rngList
'列数の取得
lngColumns = .Offset(, Columns.Count - .Column) _
.End(xlToLeft).Column - .Column + 1
If lngColumns <= 1 And .Value = "" Then
strProm = "データが有りません"
GoTo Wayout
End If
'行数の取得
lngRows = .Offset(Rows.Count - .Row, vntKeys).End(xlUp).Row - .Row
If lngRows <= 0 Then
strProm = "データが有りません"
GoTo Wayout
End If
'復帰用整列Keyを作成
ReDim vntData(1 To lngRows, 1 To 1)
For i = 1 To lngRows
vntData(i, 1) = i
Next i
'復帰用Keyの出力
.Offset(1, lngColumns) _
.Resize(lngRows).Value = vntData
'データを抽出Keyで整列
DataSort .Offset(1).Resize(lngRows, _
lngColumns + 1), .Offset(, vntKeys)
'抽出Keyデータを配列に取得
vntGroup = .Offset(1, vntKeys) _
.Resize(lngRows + 1).Value
'列見出し範囲を取得
Set rngHeader = .Resize(, lngColumns)
'列幅を取得
ReDim vntColumnWidth(lngColumns - 1)
For i = 0 To lngColumns - 1
vntColumnWidth(i) _
= .Offset(, i).EntireColumn.ColumnWidth
Next i
End With
'仮に結果と元表を同じにして置く
Set rngResult = rngList
'注目値の位置を記録
lngTop = 1
'データ行数のカウント初期値
lngCount = 1
For i = 2 To lngRows + 1
'注目値と現在値が違った場合
If vntGroup(lngTop, 1) <> vntGroup(i, 1) Then
'出力シートを設定
GetSheets CStr(vntGroup(lngTop, 1)), cstrTop, _
rngResult, rngHeader, vntColumnWidth
'データを転記
rngList.Offset(lngTop).Resize(lngCount, _
lngColumns).Copy Destination:=rngResult
'注目値の位置を記録
lngTop = i
'データ行数のカウント初期値に
lngCount = 1
Else
'データ行数のカウントを更新
lngCount = lngCount + 1
End If
Next i
With rngList
'元データを復帰
DataSort .Offset(1).Resize(lngRows, _
lngColumns + 1), .Offset(1, lngColumns)
'復帰用Key列を削除
.Offset(, lngColumns).EntireColumn.Delete
End With
strProm = "処理が完了しました"
Wayout:
'画面更新を再開
Application.ScreenUpdating = True
Set rngList = Nothing
Set rngResult = Nothing
Set rngHeader = Nothing
MsgBox strProm, vbInformation
End Sub
Private Sub DataSort(rngScope As Range, _
rngKey As Range, _
Optional lngOrientation As Long = xlTopToBottom)
rngScope.Sort _
Key1:=rngKey, Order1:=xlAscending, _
Header:=xlNo, OrderCustom:=1, MatchCase:=False, _
Orientation:=lngOrientation, SortMethod:=xlStroke
End Sub
Private Sub GetSheets(strName As String, _
strTop As String, _
rngResult As Range, _
rngHeader As Range, _
vntWidth As Variant)
Dim i As Long
Dim lngRows As Long
Dim wksMark As Worksheet
'シートの存在確認
For Each wksMark In Worksheets
If StrComp(wksMark.Name, strName, vbTextCompare) = 0 Then
Exit For
End If
Next wksMark
'もし、シートが無いなら
If wksMark Is Nothing Then
'シートを追加して、シート名を設定
Set wksMark = Worksheets.Add(After:=rngResult.Parent)
On Error Resume Next
wksMark.Name = strName
On Error GoTo 0
End If
With wksMark.Range(strTop)
'行数の取得
lngRows = .Offset(Rows.Count - .Row).End(xlUp).Row - .Row
If lngRows <= 0 Then
'列幅を設定
For i = 0 To UBound(vntWidth, 1)
.Offset(, i).EntireColumn.ColumnWidth = vntWidth(i)
Next i
'列見出しを出力
rngHeader.Copy Destination:=.Offset
'出力位置を設定
Set rngResult = .Offset(rngHeader.Rows.Count)
Else
'出力位置を設定
Set rngResult = .Offset(lngRows + 1)
End If
End With
Set wksMark = Nothing
End Sub
|
|