Есть отчет, который я извлекаю из нашей системы ERP, в котором перечислены сведения о заказе. Он содержит номер заказа, код клиента, имя клиента, дату заказа, статус заказа, общую сумму заказа, код продукта, название продукта, а также заказанное количество, цену за единицу и расширенную цену. Если заказ имеет несколько строк, то информация заголовка указывается несколько раз.
Вот как выглядят необработанные данные.
Я пытаюсь найти способ в Excel, чтобы строки заголовков не повторялись для каждой строки детализации.
Я бы предпочел, чтобы данные выглядели так, когда я закончу. По сути, каждая из строк повторяется под соответствующими строками заголовков.
Другой приемлемый формат может быть ниже. Я думаю, это может быть проще. Я смог сделать это с помощью сводной таблицы.
Я не уверен, потребуется ли для этого VBA или нет. Я пробовал выделять строки и использовать удаление дубликатов, но это перемещает все строки вместе. Любая помощь будет высоко оценена.
решение1
Я знаю, что это не приветствуется, но проблема показалась мне интересной, поэтому я просто написал код на VBA.
Попробуйте код ниже. Я установил константы для работы в примере, который вы привели, но вы можете изменить их для своего фактического приложения.
Function CompressReport()
'Settings for which columns are the header and details
Const fHC As Long = 1 'First header column number
Const lHC As Long = 6 'Last header column number
Const fDC As Long = 7 'First detail column number
Const lDC As Long = 11 'Last detail column number
'Declarations
Dim rStart&, rStop&, rNew As Long
Dim r&, c As Long
Dim ws As Worksheet
Dim wsNew As Worksheet
Dim s1$, s2 As String
'Set the source worksheet to be compressed
'(Here are a few methods to do this. Pick one.)
Set ws = Sheet1
Set ws = Worksheets(1)
Set ws = Worksheets("Sheet1")
'Add a new worksheet for our results
Set wsNew = Worksheets.Add(After:=ws)
With ws
'Copy the first row of headers
.Range(.Cells(1, fHC), .Cells(1, lHC)).Copy wsNew.Cells(1, 1)
rNew = 2
'Loop through all the rows
For rStart = 2 To ws.UsedRange.Rows.Count
'Copy the header information
.Range(.Cells(rStart, fHC), .Cells(rStart, lHC)).Copy wsNew.Cells(rNew, 1)
'Add a thick border (This wasn't in the OP but I recommend it)
With wsNew.Range(wsNew.Cells(rNew, 1), wsNew.Cells(rNew, lHC - fHC + 1)).Borders(xlEdgeTop)
.LineStyle = xlContinuous 'You could also try xlDouble
.Weight = xlThick
End With
'Collect the header information into a single unique ID
s1 = ""
For c = fHC To lHC
s1 = s1 & "|" & .Cells(rStart, c).Value
Next
'Find the next row with different information
For rStop = rStart + 1 To .UsedRange.Rows.Count
s2 = ""
For c = fHC To lHC
s2 = s2 & "|" & .Cells(rStop, c).Value
Next
If s2 <> s1 Then Exit For
Next
rStop = rStop - 1
'Copy the detail headers and information
.Range(.Cells(1, fDC), .Cells(1, lDC)).Copy wsNew.Cells(rNew + 1, 2)
.Range(.Cells(rStart, fDC), .Cells(rStop, lDC)).Copy wsNew.Cells(rNew + 2, 2)
'Increase the row we're pasting in the new worksheet
' +1 for header data, +1 for detail headers, +n for detail information
rNew = rNew + 1 + 1 + (rStop - rStart + 1)
'Increase the row we're copying in the source worksheet
rStart = rStop 'The FOR loop will iterate it +1
Next
End With
'Formatting (feel free to add to this part)
With wsNew
.Columns.AutoFit
End With
'Cleanup
Set wsNew = Nothing
Set ws = Nothing
End Function
решение2
Вот небольшой трюк для достижения вашей цели. Его можно применить к ячейкам в любом столбце. Допустим, мы начинаем с:
И мы хотим избежать всего лишнегоМайк's и т.д.Нажимаем на ячейкуА2и применить условное форматирование так, чтобы, если значение ячейки такое же, как и в ячейке над ней, сделать цвет шрифта таким же, как цвет фона ячейки:
Затем мы копируем ячейкуА2и PasteSpecialFormats вниз по столбцу. Это «скрывает» повторяющиеся значения:
Фактические данные остаются нетронутыми, меняется только отображение!
решение3
я кладу
в Лист1, и мне удалось заставить Лист2 выглядеть следующим образом:
Он использует два вспомогательных столбца, которые, конечно, можно переместить так далеко вправо, как вам хочется (или нужно), и которые можно скрыть.
- Установите
A1
(на Листе2)=Sheet1!A1
и перетащите вправо, чтобы закрыть столбцы, которые в противном случае дублировались бы на нескольких строках. В вашем примере это будет СтолбецF
. (В моем примере это СтолбецC
.) - Установите
Y2
в2
иZ2
в1
. Значение в СтолбцеY
говорит о том, что строка Лист1этотстрока извлекает данные из. СтолбецZ
—1
если это строка заголовка (извлекает данные из левых столбцов Листа1; т. е. ключевые поля),2
если это строка подзаголовка,3
если это строка дополнительных данных (извлекает данные из правых столбцов Листа1) и0
если это пустая строка (под последней строкой данных). - Установите
A2
на=IF($Z2=1, INDEX(Sheet1!A:A, $Y2), "")
. Если применимо, перетащите вправо, чтобы закрыть столбцы, которые используются только для ключевых данных. В вашем примере это неприменимо, поскольку у вас есть неключевые данные, начинающиеся в ColumnB
. (В моем примере это происходит через ColumnB
.) Это реализует определения вспомогательных столбцов: еслиZ
равно1
, извлекаем ключевые данные из Sheet1, в противном случае пусто. В моем примере я установил
C2
значение=CHOOSE($Z2+1, "", INDEX(Sheet1!C:C, $Y2), Sheet1!D$1, INDEX(Sheet1!D:D, $Y2))
В вашем примере вам следует установить
B2
значение=CHOOSE($Z2+1, "", INDEX(Sheet1!B:B, $Y2), Sheet1!G$1, INDEX(Sheet1!G:G, $Y2))
отражая два столбца Листа1,
B
из которых может извлекаться Столбец Листа2:- Столбец
B
(«Код клиента»), или - Столбец
G
(«Код продукта»)
Опять же, это просто делает то, что вспомогательные столбцы говорят ему делать. Мы добавляем
1
кZ
значению для отображения0
,1
,2
, и3
к1
,2
,3
, и4
.CHOOSE
использует первый аргумент для индексации в следующих аргументах, поэтому- Если
Z
есть0
, пусто, - Если
Z
есть1
, получить ключевые данные, - Если
Z
есть2
, получить заголовок из строки Лист11
и - Если
Z
да3
, получить неключевые данные.
- Столбец
Установить
Y3
в=IF($Z2<3, $Y2, $Y2+1)
иZ3
в=IF($Z2=0, 0, IF($Z2<3, $Z2+1, IF(INDEX(Sheet1!A:A,$Y2+1)="", 0, IF(INDEX(Sheet1!A:A,$Y2)=INDEX(Sheet1!A:A,$Y2+1), 3, 1))))
(все на одной строке). Они говорят, что если
Z
значение в предыдущей строке равно1
или2
(или0
), установите этоY
значение таким же, как значение предыдущей строки. Это происходит потому, что каждая строка в таблице вашей базы данных (каждый набор уникальных значений в столбцахA
-F
на Листе1) приводит к появлению как минимум трех строк на Листе2. В противном случае увеличьте значениеY
, чтобы обратиться к следующей строке на Листе1.Если предыдущее
Z
значение равно0
, то мы закончили и заполняем нулями. Если предыдущееZ
значение равно1
или2
, переходим к следующему значению. В противном случае смотрим на ключевые данные Sheet1. Если они пустые, предполагаем, что мы находимся в конце данных, и устанавливаемZ
.0
Если они такие же, как в предыдущей строке, используем ,3
чтобы продолжить то, что мы делаем. В противном случае мы попадаем в новый набор уникальных значений, поэтому перезапускаем цикл с1
.- Проведите пальцем вниз достаточно далеко, чтобы получить все данные.
Если ваши уникальные значения не являются индивидуальными (например, если у вас может быть A4
=, A5
но B4
≠ B5
), расширьте тесты в столбце Z
, чтобы проверить столько столбцов, сколько вам нужно (объединяя их с AND(…)
).
Разумеется, я использовал условное форматирование с формулой =$Z2=2
, чтобы соответствующим образом отформатировать подзаголовки.