# Multi-Row Headers → Single Row Headers

> Headers span multiple rows (e.g., Category + Subcategory, Quarter + Metric).

- Skill: `tools-only/multi-row-headers-single-row-headers` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add tools-only/multi-row-headers-single-row-headers`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tools-only/multi-row-headers-single-row-headers/raw
- Safety review: pending (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: tools-only (https://skillmd.com/u/tools-only)
- Updated: 2026-09-29
- Page: https://skillmd.com/skills/tools-only/multi-row-headers-single-row-headers

---

# Multi-Row Headers → Single Row Headers

## Table of Contents

1. [When to Use](#when-to-use)
2. [Important Decision Framework](#important-decision-framework)
3. [Method 1: Separate Header + Append (Recommended)](#method-1-separate-header--append-recommended)
4. [Method 2: Transpose Method (Auto but Complex)](#method-2-transpose-method-auto-but-complex)
5. [Method Comparison](#method-comparison)
6. [Quick Decision Tree](#quick-decision-tree)

---

## When to Use

Headers span multiple rows (e.g., Category + Subcategory, Quarter + Metric).

**Examples**:
```
| Customer          |          | Seller         |          |          |
| ID    | Name      | ID       | Name   | Age   |
|-------|-----------|----------|--------|-------|
| C001  | John      | S01      | Alice  | 28    |
```

```
| Q1             | Q1      | Q2             | Q2      |
| Sales | Units  | Sales   | Units   |
|-------|--------|---------|---------|
| 1000  | 50     | 1200    | 60      |
```

---

## Important Decision Framework

**First, identify your data structure:**

### 1. Transaction data (Each row = 1 transaction, already long format)

**Example**: Sales transactions with Customer→ID/Name, Seller→ID/Name/Age

**Goal**: Fix column names only, **NO unpivot needed**

**Recommended**: ✅ **Method 1 (Separate Header + Append)**

**Why**: 
- Simple and reliable
- You just need correct column names
- No need for complex unpivot/pivot operations

---

### 2. Wide format data (Metrics spread across columns)

**Example**: Q1 Sales, Q1 Units, Q2 Sales, Q2 Units

**Goal**: Fix headers **AND** unpivot to long format

**Can use**: 
- ✅ **Method 1** (reliable) - Fix headers first, then unpivot separately
- 🟡 **Method 2** (auto but complex) - Combines header fix + unpivot in one flow

**Why**: 
- Method 1: More steps but clearer, works every time
- Method 2: Fewer queries but complex, many steps, easy to make mistakes

---

### 3. Mixed hierarchy (Some columns 1 level, some 2 levels)

**Example**: Date/Product/Price (1 level) + Customer→ID/Name (2 levels)

**Recommended**: ✅ **Method 1 (Separate Header + Append)**

**Why**: 
- Method 2 (Transpose) doesn't work well with mixed structures
- Method 1 gives you full control over exact column names

---

## Method 1: Separate Header + Append (Recommended)

### When to use
- ✅ Mixed hierarchy
- ✅ Transaction data (no unpivot needed)
- ✅ When you want reliability
- ✅ When you prefer clear, simple steps

### Key principle
Manually create correct 1-row headers, then append with body

### Step-by-Step Guide

#### Step 1: Create "body" query (data only)

```
1. Get Data → From Table/Range
2. ⚠️ DO NOT tick "My table has headers"
3. Delete auto "Changed Type" step (it has wrong column names)
4. Home → Remove Rows → Remove Top Rows → 2 (or however many header rows)
5. Now you have: Column1, Column2, Column3, ... with only data rows
6. Right-click query → Rename → "body"
```

**Result**: Clean data table with generic column names (Column1, Column2, etc.)

---

#### Step 2: Create "header" query (correct headers)

**In Excel**: Create new table with 1 row of correct headers

**Example for transaction data with multi-row headers**:
```
วันที่ | สินค้า | ราคาต่อชิ้น | จำนวนชิ้น | วิธีการชำระเงิน | ลูกค้า_รหัส | ลูกค้า_ชื่อ | ผู้ขาย_รหัส | ผู้ขาย_ชื่อ | ผู้ขาย_อายุ
```

**Example for wide format data that needs unpivot**:
```
Product | Payment | Q1_Sales | Q1_Units | Q2_Sales | Q2_Units
```

**In Power Query**:
```
1. Get Data → From Table/Range (from your 1-row header table)
2. ⚠️ DO NOT tick "My table has headers"
3. Delete auto "Changed Type" step
4. Now you have: Column1, Column2, Column3, ... (same structure as body!)
5. Right-click query → Rename → "header"
```

**Critical**: Header query must have exact same number of columns as body query, with same Column1, Column2, Column3 structure

---

#### Step 3: Append queries

```
1. Select "header" query
2. Home → Append Queries → Append Queries as New
3. First table: header
   Second table: body
4. OK
5. Result: Row 1 = correct headers, Row 2+ = data
6. Right-click new query → Rename → "final"
```

---

#### Step 4: Promote headers and set types

```
1. Home → Use First Row as Headers
2. Set data types:
   - Date columns: Date (Using Locale!)
   - Amount columns: Decimal Number (future-proof!)
   - Count columns: Whole Number (if truly no decimals)
   - Others: Text
3. Done! ✅
```

---

### If you have wide format data: Continue with unpivot

**For wide format** (Q1_Sales, Q1_Units, Q2_Sales, Q2_Units):

```
1. Unpivot:
   - Select "Product" and "Payment" columns
   - Transform → Unpivot Other Columns
   - You get: Attribute (Q1_Sales, Q1_Units, ...) and Value

2. Split Column:
   - Select "Attribute" column
   - Transform → Split Column → By Delimiter "_"
   - Choose "At the left-most delimiter"
   - You get: Attribute.1 (Q1, Q2) and Attribute.2 (Sales, Units)

3. Rename:
   - Attribute.1 → "Quarter"
   - Attribute.2 → "Metric"

4. Pivot Column:
   - Select "Metric" column
   - Transform → Pivot Column
   - Values Column: "Value"
   - Advanced Options → Don't Aggregate
   - Result: Product | Payment | Quarter | Sales | Units

Done! ✅
```

---

### Why Method 1 works

**Concept**: Bypass the complex header structure by creating correct headers separately

**Benefits**:
- ✅ Always works, no matter how complex the hierarchy
- ✅ Clear - you control exactly what headers should be
- ✅ Flexible - works with mixed hierarchy, transaction data, any structure
- ✅ Easy to understand - simple append operation

**Trade-off**: 
- 🟡 Must maintain 1-row header definition yourself
- 🟡 Two queries to manage (header + body)

**Best for**: Mixed hierarchy, transaction data, when you want reliability

---

## Method 2: Transpose Method (Auto but Complex)

### When to use
- ✅ Uniform hierarchy (all columns have same parent-child structure)
- ✅ You want automated solution
- ⚠️ NOT suitable for: Mixed hierarchy, transaction data

### Key principle
Use Transpose to leverage Fill Down (since Fill Right doesn't exist), then manipulate and transpose back

### Step-by-Step Guide

#### Step 1: Separate body (same as Method 1)

```
1. Get Data → From Table/Range
2. DO NOT tick "My table has headers"
3. Delete auto "Changed Type" step
4. Remove Top Rows → N (number of header rows)
5. Rename → "body"
```

---

#### Step 2: Process headers automatically

```
1. Duplicate original query → Rename "headers_raw"
2. Keep Top Rows → 2 (or number of header rows)
3. Delete auto "Changed Type" step
4. Transpose (converts columns to rows)
   - Each original column becomes a row
   - Column1 = parent category, Column2 = subcategory
```

**After Transpose example**:
```
| Column1 | Column2 |
|---------|---------|
| Q1      | Sales   |
| Q1      | Units   |
| Q2      | Sales   |
| Q2      | Units   |
```

```
5. Fill Down on Column1 (fills parent categories)
   - Select Column1
   - Transform → Fill → Down
   - This fills null cells in parent category
```

**After Fill Down**:
```
| Column1 | Column2 |
|---------|---------|
| Q1      | Sales   |
| Q1      | Units   |
| Q2      | Sales   |
| Q2      | Units   |
```

```
6. ✅ CRITICAL: Trim whitespace BEFORE merging (Best Practice!)
   - Select Column1
   - Transform → Format → Trim
   - Select Column2  
   - Transform → Format → Trim
   - This removes leading/trailing spaces from both columns
```

**Why trim first?**
- Headers may have spaces: "Status " (trailing) or " Sales" (leading)
- **Without trim before merge**: "Status " + "-" + " Jan" → "Status - Jan" ❌ (space around dash!)
- **With trim before merge**: "Status" + "-" + "Jan" → "Status-Jan" ✅ (clean delimiter)

```
7. Merge Columns: Column1 + Column2
   - Select Column1
   - Hold Ctrl, select Column2
   - Transform → Merge Columns
   - Separator: Choose delimiter:
     - "_" (underscore) - most common
     - "-" (dash) - also common
     - " " (space) - less recommended
   - Example result: "Q1_Sales", "Q1_Units", "Q2_Sales", "Q2_Units"
```

```
8. Trim delimiter (if blank cells exist)
   - If Row 2 had blank cells (common for Title/Author columns)
   - After merge you'll get: "Title-" or "-Jan" (delimiter at edge)
   - Transform → Replace Values:
     - Find: "^-" (leading dash) - use regex if available
     - Find: "-$" (trailing dash) - use regex if available
   - Or simpler: Right-click column → Transform → use M code
   - Formula bar: Text.Trim([Merged], "-")
   - Example: "Title-" → "Title", "Q1-Sales" → "Q1-Sales" (unchanged)
```

```
9. Transpose back (converts back to columns)
   - Transform → Transpose
   - You now have single-row headers with combined names
10. Rename → "header"
```

---

#### Step 3: Append with body (same as Method 1)

```
1. Select "header" query
2. Home → Append Queries → Append Queries as New
3. First table: header, Second table: body
4. Home → Use First Row as Headers
5. Set data types correctly
```

---

#### Step 4: If wide format, continue with unpivot

For wide format (Q1_Sales, Q1_Units, Q2_Sales, Q2_Units):

```
1. Unpivot Other Columns
   - Select ID columns (Product, Payment, etc.)
   - Transform → Unpivot Other Columns
   - Result: Attribute (Q1_Sales, ...) and Value

2. Split Column by Delimiter "_" (or "-")
   - Select "Attribute"
   - Split by delimiter at left-most delimiter
   - Result: Quarter (Q1, Q2) and Metric (Sales, Units)

3. ⚠️ CHECK: Do you need Index column?
   
   **✅ You DON'T need Index if:**
   - Each group (ID columns + Quarter/Month) has each metric ONLY ONCE
   - Example: Book A + Jan has Sales=1 value, Units=1 value ✅
   - In this case: Skip to step 4 (Pivot) directly
   
   **❌ You NEED Index if:**
   - Same group has same metric MULTIPLE TIMES (transaction data)
   - Example: Phone + Q1 has Sales=2 values (100, 150)
   - AND you want Don't Aggregate (keep all rows separate)
   - In this case: Add Index column
   
   **How to check:**
   - Look at your data before pivot
   - Count: How many rows for "Book A + Jan + Sales"?
   - If 1 row → No Index needed ✅
   - If 2+ rows → Need Index (or use Aggregate) ❌
   
   **If Index is needed:**
   ```
   Add Column → Index Column → From 0
   Pattern depends on your data:
   - From 0: If every row is separate transaction (0,1,2,3,...)
   - Custom pattern: If transactions span multiple rows (1,1,2,2,...)
     (requires M code for complex patterns)
   ```

4. Pivot Column
   - Select "Metric" column
   - Transform → Pivot Column
   - Values Column: "Value"
   - Advanced Options → Don't Aggregate (if each group has 1 value per metric)
   - OR → Choose Aggregate function (Sum, Average, etc.) if needed
   - Result: Product | Payment | Quarter | Sales | Units

5. Remove Index column (if you added it in step 3)
   - Right-click Index → Remove
```

**Notes on Aggregate vs Don't Aggregate:**
- **Don't Aggregate**: Use when each group has unique values
  - Example: Book A + Jan → Sales=1 value, Units=1 value
  - No Index needed in this case ✅
- **Aggregate (Sum/Average/etc.)**: Use when you want to combine multiple values
  - Example: Phone + Q1 → Sales=2 values (100, 150) → Sum = 250
  - No Index needed - aggregation handles multiple values ✅
- **Don't Aggregate + Multiple values**: Requires Index
  - Example: Phone + Q1 → Sales=2 values but want 2 separate rows
  - Must add Index to distinguish transactions ❌

---

### Why Method 2 works

**Concept**: Transpose to use Fill Down (since Fill Right doesn't exist), manipulate, transpose back

**Benefits**:
- ✅ More automated - headers created from original data
- ✅ No need to manually define headers

**Trade-off**:
- ❌ Complex - many steps, easy to make mistakes
- ❌ Doesn't work well with mixed hierarchy
- ❌ May need workarounds for pivot aggregation
- ❌ Harder to troubleshoot if something goes wrong

**Best for**: Uniform hierarchy + wide format data, when comfortable with complex transformations

---

## Method Comparison

| Aspect | Method 1: Separate + Append | Method 2: Transpose |
|--------|------------------------------|---------------------|
| **Reliability** | ✅ Always works | 🟡 Depends on structure |
| **Complexity** | ✅ Simple, clear steps | ❌ Many steps, complex |
| **Mixed hierarchy** | ✅ Perfect for this | ❌ Doesn't work well |
| **Transaction data** | ✅ Recommended | ⚠️ Overkill, not suitable |
| **Wide format data** | ✅ Works (then unpivot) | 🟡 Can work but complex |
| **Maintenance** | 🟡 Must maintain header | ✅ Auto-updates |
| **Beginner-friendly** | ✅ Easy to understand | ❌ Can be confusing |
| **Troubleshooting** | ✅ Easy to debug | ❌ Hard to find issues |

---

## Quick Decision Tree

```
START: Do you have multi-row headers?
  ↓
  ├─→ Mixed hierarchy (some 1-level, some 2-level)?
  │   → ✅ Use Method 1 (Separate + Append)
  │
  ├─→ Transaction data (no unpivot needed)?
  │   → ✅ Use Method 1 (Separate + Append)
  │
  ├─→ Wide format (need to unpivot)?
  │   ├─→ Want reliability?
  │   │   → ✅ Use Method 1 (Separate + Append + Unpivot)
  │   │
  │   └─→ Want automation + comfortable with complexity?
  │       → 🟡 Use Method 2 (Transpose Method)
  │
  └─→ Uniform hierarchy + comfortable with many steps?
      → 🟡 Consider Method 2 (Transpose Method)
      → But Method 1 is still safer!
```

---

## General Recommendation

**Start with Method 1 (Separate + Append)**. It's:
- ✅ Reliable - works for all cases
- ✅ Clear - easy to understand what's happening
- ✅ Maintainable - easy to fix if issues arise

**Use Method 2 only if**:
- You have uniform structure (all columns same hierarchy)
- You want automation (headers update automatically)
- You're comfortable with complex multi-step transformations
- You've tested thoroughly with sample data

---

## Remember

⚠️ **Always test with new data** before trusting the query!

⚠️ **For wide format**: Fix headers FIRST, then unpivot separately - don't try to do everything at once

⚠️ **For transaction data**: Method 1 is simpler - you just need correct column names, no unpivot

⚠️ **When in doubt**: Choose Method 1 (Separate + Append) - it always works! 🎯

