| date | region | product | quantity | revenue | cost |
|---|---|---|---|---|---|
| 2026-10-30 | North | Sprocket | 20 | 300 | 240 |
22 Adding rows
A late order arrives in a table of its own, so where do its rows go? add_rows stacks another table underneath this one. Nothing is matched and no column is added; the answer holds every row of both tables.
The late order is more, one row with the same columns as sales:
run('
sales
then add_rows more
then sort [date] descending
then take 3
')| date | region | product | quantity | revenue | cost |
|---|---|---|---|---|---|
| 2026-10-30 | North | Sprocket | 20 | 300 | 240 |
| 2026-10-02 | West | Widget | 5 | 125 | 50 |
| 2026-09-15 | East | Gadget | 1 | 60 | 40 |
sales |> add_rows(more) |> sort(descending(date)) |> take(3)| date | region | product | quantity | revenue | cost |
|---|---|---|---|---|---|
| 2026-10-30 | North | Sprocket | 20 | 300 | 240 |
| 2026-10-02 | West | Widget | 5 | 125 | 50 |
| 2026-09-15 | East | Gadget | 1 | 60 | 40 |
sales >> add_rows(more) >> sort(descending(col.date)) >> take(3)| date | region | product | quantity | revenue | cost |
|---|---|---|---|---|---|
| 2026-10-30 | North | Sprocket | 20 | 300 | 240 |
| 2026-10-02 | West | Widget | 5 | 125 | 50 |
| 2026-09-15 | East | Gadget | 1 | 60 | 40 |
sales then add_rows more then sort [date] descending then take 3
The sort is there so the page can show the stacking worked: newest first, and the late order is the first row of the answer.
The other table can even be this one, which is how a table is doubled:
run('
sales
then add_rows sales
then summarize [rows] as row_count()
')| rows |
|---|
| 30 |
sales |> add_rows(sales) |> summarize(rows = row_count())| rows |
|---|
| 30 |
sales >> add_rows(sales) >> summarize(rows = row_count())| rows |
|---|
| 30 |
Every row appears twice, and both copies stay: add_rows never removes anything. Dropping repeats has a verb of its own, drop_duplicates.
Both tables need the same columns, and each column has to hold the same kind of thing on both sides. A column on one side only is refused rather than filled in with missing values, because a half-empty column that says nothing is how a mistake survives to the end of a pipeline.
late <- data.frame(region = "North")
collect(sales |> add_rows(late))Error:
!
illegal: `add_rows` needs both tables to have the same columns: this table has date, product, quantity, revenue, cost and `late` does not. Add what is missing, or drop it with `pick`
|
2 | then add_rows late
| ^^^^^^^^^^^^^
late = pd.DataFrame({"region": ["North"]})
try:
collect(sales >> add_rows(late))
except GodError as refusal:
print(refusal)
illegal: `add_rows` needs both tables to have the same columns: this table has date, product, quantity, revenue, cost and `late` does not. Add what is missing, or drop it with `pick`
|
2 | then add_rows late
| ^^^^^^^^^^^^^
The message names the columns one side lacks, so the repair starts with the tables rather than with the sentence: make them agree, and the verb has nothing left to refuse.