tdb - a text database
tdb is an in-memory non-relational "Text DataBase" (tdb) and
reporting language that uses N-dimensional 
AVL trees.
to approximate a sparse, N-dimensional hyper-cube.
Here are some trivial examples to illustrate a few of the most basic tdb features
and capabilities.
In particular, note how the foreach and sort statements are used.
Full details can be found in the 
tdb Users' Guide.
Download tdb from github.
tdb Usage Message
$ tdb
usage (v0.1.2):
tdb -f field_file -s select_file [OPTIONS] data_file [...]
    or
tdb -f field_file -r report_file [OPTIONS] data_file [...]
where OPTIONS are any of:
  -v                                    : verbose/statistics mode
  -d delimiter_character                : data file field delimiter character
  -1                                    : skip line #1 of delimited data file(s)
  -q quote_character (default ")        : quote character for delimited data file(s)
  -o output_file                        : output file
  -I variable_name=integer_value        : define an integer cmd line variable
  -F variable_name=floating_point_value : define a float cmd line variable
  -S variable_name=string_value         : define a string cmd line variable
Notes:
  Use `-' to specify stdin as a `data_file'
  Define variables like this: -I foobar=42     (ie, no spaces around the `=')
tdb Copyright (C) 1991-2016 James S. Crook
This program comes with ABSOLUTELY NO WARRANTY.
This is free software, and you are welcome to redistribute it under certain conditions.
This program is licensed under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or (at your option) any
later version (see <http://www.gnu.org/licenses/>).
Expenditure Fields File (exp.f)
string  category
int     date
string  penguin
float   amount
string  description
Expenditure Data File (exp.d)
"Air Fare"      20151201        Tux             3000.00 "Vladivostok"
"Air Fare"      20151203        Tux             2500.00 "Sydney"
"Air Fare"      20151206        Tux             3500.00 "Hong Kong"
#
"Coffee"        20151201        Tux                3.50 "Carpe Diem"
"Coffee"        20151202        Tux                3.50 "Carpe Diem"
"Coffee"        20151203        Tux                3.50 "Carpe Diem"
"Coffee"        20151204        Tux                3.50 "Carpe Diem"
"Coffee"        20151205        Tux                3.50 "Carpe Diem"
"Coffee"        20151206        Tux                3.50 "Carpe Diem"
"Coffee"        20151207        Tux                3.50 "Carpe Diem"
"Coffee"        20151203        Tux                3.50 "Carpe Diem"
"Coffee"        20151205        Tux                3.50 "Carpe Diem"
#
"Fuel"          20151203        Tux               70.00 "Lamborghini"
"Fuel"          20151205        Tux               80.00 "Lamborghini"
"Fuel"          20151207        Tux               90.00 "Lamborghini"
"Fuel"          20151202        Tux               70.00 "Maserati"
"Fuel"          20151204        Tux               80.00 "Maserati"
"Fuel"          20151206        Tux               90.00 "Maserati"
#
"Train Ticket"  20151202        Tux               10.50 "Office"
"Train Ticket"  20151204        Tux               10.50 "Office"
"Train Ticket"  20151206        Tux               10.50 "Office"
"Train Ticket"  20151203        Tux               19.20 "Football game"
####################################################################
"Entertainment" 20151203        Tux               81.00 "Wine"
"Entertainment" 20151204        Tux               83.00 "Wine"
"Entertainment" 20151205        Tux               85.00 "Wine"
"Entertainment" 20151206        Tux               57.00 "Wine"
"Entertainment" 20151207        Tux               89.00 "Wine"
"Entertainment" 20151203        Tux               41.00 "Beer"
"Entertainment" 20151204        Tux               43.00 "Beer"
"Entertainment" 20151205        Tux               45.00 "Beer"
"Entertainment" 20151206        Tux               47.00 "Beer"
"Entertainment" 20151207        Tux               49.00 "Beer"
"Entertainment" 20151204        Tux               13.00 "Movie"
####################################################################
"Coffee"        20151201        Tuxette            3.50 "Morning Java"
"Coffee"        20151202        Tuxette            3.50 "Morning Java"
"Coffee"        20151203        Tuxette            3.50 "Morning Java"
"Coffee"        20151204        Tuxette            3.50 "Morning Java"
"Coffee"        20151205        Tuxette            3.50 "Morning Java"
"Coffee"        20151206        Tuxette            3.50 "Morning Java"
"Coffee"        20151207        Tuxette            3.50 "Morning Java"
"Coffee"        20151203        Tuxette            3.50 "Morning Java"
"Coffee"        20151205        Tuxette            3.50 "Morning Java"
"Entertainment" 20151201        Tuxette           60.50 "Cocktails"
"Entertainment" 20151202        Tuxette           85.50 "Wine"
"Entertainment" 20151206        Tuxette           62.00 "Cocktails"
"Entertainment" 20151206        Tuxette          190.50 "Restaurant"
"Bills"         20151202        Tuxette          400.50 "Electricity"
"Bills"         20151203        Tuxette          125.50 "Gas"
"Bills"         20151203        Tuxette          120.50 "Water"
"Bills"         20151206        Tuxette          250.50 "Garbage"
"Clothing"      20151201        Tuxette          350.50 "Leather Jacket"
"Clothing"      20151206        Tuxette          270.50 "Lingerie"
"Groceries"     20151206        Tuxette          389.50 "Weekly shop"
"Groceries"     20151206        Tuxette           49.50 "Liquor"
"Air Fare"      20151203        Tuxette          530.00 "Las Vegas"
"Entertainment" 20151204        Tuxette           13.00 "Movie"
####################################################################
"Food"          20151201        Tuxina             4.50 "School lunch"
"Food"          20151202        Tuxina             4.50 "School lunch"
"Food"          20151203        Tuxina             4.50 "School lunch"
"Food"          20151204        Tuxina             4.50 "School lunch"
"Food"          20151205        Tuxina             4.50 "School lunch"
"Supplies"      20151201        Tuxina             8.50 "Pencils"
"Supplies"      20151202        Tuxina            85.50 "Books"
"Fun"           20151206        Tuxina             3.50 "Swimming pool"
"Entertainment" 20151204        Tuxina            13.00 "Movie"
"Train Ticket"  20151208        Tuxina             9.30 "School"
"Train Ticket"  20151209        Tuxina             9.30 "School"
"Train Ticket"  20151210        Tuxina             9.30 "School"
"Train Ticket"  20151211        Tuxina             9.30 "School"
"Train Ticket"  20151212        Tuxina             9.30 "School"
####################################################################
"Supplies"      20151201        "Tux Jr."         82.50 "Books"
"Supplies"      20151203        "Tux Jr."        850.50 "Laptop"
"Supplies"      20151205        "Tux Jr."        208.50 "SSD drive"
"Supplies"      20151205        "Tux Jr."         10.50 "Crayons"
"Food"          20151201        "Tux Jr."          4.50 "School lunch"
"Food"          20151202        "Tux Jr."          4.50 "School lunch"
"Food"          20151203        "Tux Jr."          4.50 "School lunch"
"Food"          20151204        "Tux Jr."          4.50 "School lunch"
"Food"          20151205        "Tux Jr."          4.50 "School lunch"
"Food"          20151203        "Tux Jr."          3.50 "School snack"
"Fun"           20151207        "Tux Jr."         33.40 "Ice sailing"
"Entertainment" 20151204        "Tux Jr."         13.00 "Movie"
"Train Ticket"  20151208        "Tux Jr."          9.30 "School"
"Train Ticket"  20151209        "Tux Jr."          9.30 "School"
"Train Ticket"  20151210        "Tux Jr."          9.30 "School"
"Train Ticket"  20151211        "Tux Jr."          9.30 "School"
"Train Ticket"  20151212        "Tux Jr."          9.30 "School"
####################################################################
"Entertainment" 20151206        Tux             1444.44 "Beer"
"Entertainment" 20151206        Tux             3450.00 "Booze"
"Entertainment" 20151206        Tux             1235.00 "Cigars"
"Entertainment" 20151206        Tux              850.00 "Cognac"
"Entertainment" 20151206        Tux             3500.00 "Cocaine"
"Entertainment" 20151206        Tux             1900.00 "Strippers"
"Entertainment" 20151206        Tux             2400.00 "Hookers"
"Entertainment" 20151206        Tux             7531.50 "Restaurant"
"Entertainment" 20151206        Tux             2468.42 "Can't remember"
"Firearms"      20151206        Tux             1500.00 "Glock 19"
"Firearms"      20151207        Tux             9500.00 "RPG Launcher"
"Firearms"      20151209        Tux             2550.00 "Ammo"
####################################################################
"Coffee"        20151208        Tux                3.50 "Carpe Diem"
"Coffee"        20151209        Tux                3.50 "Carpe Diem"
"Coffee"        20151210        Tux                3.50 "Carpe Diem"
"Coffee"        20151211        Tux                3.50 "Carpe Diem"
"Coffee"        20151212        Tux                3.50 "Carpe Diem"
"Coffee"        20151213        Tux                3.50 "Carpe Diem"
"Coffee"        20151214        Tux                3.50 "Carpe Diem"
Expenditure by Category and Penguin - a Trivial Report Program
aggregate(category, penguin);
foreach(category:) {
    printf("%-15s", category);
    foreach(penguin:)
        printf("%10.2f", sum(amount: category, penguin));
    printf("\n");
}
Running tdb in report mode:
$ tdb -f exp.f -r exp_cat_penguin_basic.r exp.d
Air Fare          9000.00      0.00    530.00      0.00
Bills                0.00      0.00    897.00      0.00
Clothing             0.00      0.00    621.00      0.00
Coffee              56.00      0.00     31.50      0.00
Entertainment    25412.36     13.00    411.50     13.00
Firearms         13550.00      0.00      0.00      0.00
Food                 0.00     26.00      0.00     22.50
Fuel               480.00      0.00      0.00      0.00
Fun                  0.00     33.40      0.00      3.50
Groceries            0.00      0.00    439.00      0.00
Supplies             0.00   1152.00      0.00     94.00
Train Ticket        50.70     46.50      0.00     46.50
This report output consists of rows of expenditure by category with a column for each penguin.
It would be much more useful if it had a title, column headers, totals by category, totals by
penguin and if the categories were further broken down by expenditure description. For example...
Expenditure by Category, Description and Penguin
aggregate(penguin, category, description);
printf("Tux Family Expenditure Report by Penguin: %s\n\n",
        formatdate("%d-%b-%y", reportdate()));
sort(category: sum(amount: category));
sort(penguin: sum(amount: penguin));
foreach(category:) {
    sort(description: sum(amount: category, description));
    printf("%-15s%8s", category, "Count");
    foreach(penguin:) {
        printf("%10s",  penguin);
    }
    printf("%10s (%d) items\n", "Total", number(description: category));
    foreach(description: category) {
        printf("%15s%8d", description, count(category, description));
        foreach(penguin:) {
            printf("%10.2f", sum(amount: category, description, penguin));
        }
        printf("%10.2f\n", sum(amount: category, description));
    }
    printf("%-15s%8d", "Subtotal", count(category));
    foreach(penguin:) {
        printf("%10.2f", sum(amount: category, penguin));
    }
    printf("%10.2f\n\n", sum(amount: category));
}
printf("%-15s%8d", "Total", count());
foreach(penguin:) {
    printf("%10.2f", sum(amount: penguin));
}
printf("%10.2f\n", sum(amount:));
Note the use of sum, count and number to perform the calculations -
without using any variables! Also, the categories are sorted by the total category
spend (ascending), the descriptions within each category are sorted by those totals (ascending),
and the penguins are sorted by their total spend (ascending).
$ tdb -f exp.f -r exp_cat_descr_penguin.r exp.d
Tux Family Expenditure Report by Penguin: 19-Jun-22
Fun               Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (2) items
  Swimming pool       1      3.50      0.00      0.00      0.00      3.50
    Ice sailing       1      0.00     33.40      0.00      0.00     33.40
Subtotal              2      3.50     33.40      0.00      0.00     36.90
Food              Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (2) items
   School snack       1      0.00      3.50      0.00      0.00      3.50
   School lunch      10     22.50     22.50      0.00      0.00     45.00
Subtotal             11     22.50     26.00      0.00      0.00     48.50
Coffee            Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (2) items
   Morning Java       9      0.00      0.00     31.50      0.00     31.50
     Carpe Diem      16      0.00      0.00      0.00     56.00     56.00
Subtotal             25      0.00      0.00     31.50     56.00     87.50
Train Ticket      Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (3) items
  Football game       1      0.00      0.00      0.00     19.20     19.20
         Office       3      0.00      0.00      0.00     31.50     31.50
         School      10     46.50     46.50      0.00      0.00     93.00
Subtotal             14     46.50     46.50      0.00     50.70    143.70
Groceries         Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (2) items
         Liquor       1      0.00      0.00     49.50      0.00     49.50
    Weekly shop       1      0.00      0.00    389.50      0.00    389.50
Subtotal              2      0.00      0.00    439.00      0.00    439.00
Fuel              Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (2) items
    Lamborghini       3      0.00      0.00      0.00    240.00    240.00
       Maserati       3      0.00      0.00      0.00    240.00    240.00
Subtotal              6      0.00      0.00      0.00    480.00    480.00
Clothing          Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (2) items
       Lingerie       1      0.00      0.00    270.50      0.00    270.50
 Leather Jacket       1      0.00      0.00    350.50      0.00    350.50
Subtotal              2      0.00      0.00    621.00      0.00    621.00
Bills             Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (4) items
          Water       1      0.00      0.00    120.50      0.00    120.50
            Gas       1      0.00      0.00    125.50      0.00    125.50
        Garbage       1      0.00      0.00    250.50      0.00    250.50
    Electricity       1      0.00      0.00    400.50      0.00    400.50
Subtotal              4      0.00      0.00    897.00      0.00    897.00
Supplies          Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (5) items
        Pencils       1      8.50      0.00      0.00      0.00      8.50
        Crayons       1      0.00     10.50      0.00      0.00     10.50
          Books       2     85.50     82.50      0.00      0.00    168.00
      SSD drive       1      0.00    208.50      0.00      0.00    208.50
         Laptop       1      0.00    850.50      0.00      0.00    850.50
Subtotal              6     94.00   1152.00      0.00      0.00   1246.00
Air Fare          Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (4) items
      Las Vegas       1      0.00      0.00    530.00      0.00    530.00
         Sydney       1      0.00      0.00      0.00   2500.00   2500.00
    Vladivostok       1      0.00      0.00      0.00   3000.00   3000.00
      Hong Kong       1      0.00      0.00      0.00   3500.00   3500.00
Subtotal              4      0.00      0.00    530.00   9000.00   9530.00
Firearms          Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (3) items
       Glock 19       1      0.00      0.00      0.00   1500.00   1500.00
           Ammo       1      0.00      0.00      0.00   2550.00   2550.00
   RPG Launcher       1      0.00      0.00      0.00   9500.00   9500.00
Subtotal              3      0.00      0.00      0.00  13550.00  13550.00
Entertainment     Count    Tuxina   Tux Jr.   Tuxette       Tux     Total (12) items
          Movie       4     13.00     13.00     13.00     13.00     52.00
      Cocktails       2      0.00      0.00    122.50      0.00    122.50
           Wine       6      0.00      0.00     85.50    395.00    480.50
         Cognac       1      0.00      0.00      0.00    850.00    850.00
         Cigars       1      0.00      0.00      0.00   1235.00   1235.00
           Beer       6      0.00      0.00      0.00   1669.44   1669.44
      Strippers       1      0.00      0.00      0.00   1900.00   1900.00
        Hookers       1      0.00      0.00      0.00   2400.00   2400.00
 Can't remember       1      0.00      0.00      0.00   2468.42   2468.42
          Booze       1      0.00      0.00      0.00   3450.00   3450.00
        Cocaine       1      0.00      0.00      0.00   3500.00   3500.00
     Restaurant       2      0.00      0.00    190.50   7531.50   7722.00
Subtotal             27     13.00     13.00    411.50  25412.36  25849.86
Total               106    179.50   1270.90   2930.00  48549.06  52929.46
Expenditure by Category and Date
In this report, sort is used to order the sum of expenditure by category, decreasing.
aggregate(category, date);
function displaylines() {
    printf("---------------");
    foreach(date:) {
        printf(" ---------");
    }
    printf(" ---------\n", "Total");
}
printf("Tux Family Expenditure Report - %s\n\n",
        formatdate("%d-%b-%y", reportdate()));
displaylines();
printf("%-15s", "Category");
foreach(date:) {
    printf("%10s", formatdate("%d-%b-%y", date));
}
printf("%10s\n", "Total");
displaylines();
sort(category: -sum(amount: category));
foreach(category:) {
    printf("%-15s", category);
    foreach(date:) {
        cat_date_amt = sum(amount: category, date);
        if (cat_date_amt != 0) {
            printf("%10.2f", cat_date_amt);
        } else {
            printf("%10s", "");
        }
    }
    printf("%10.2f\n", sum(amount: category));
}
displaylines();
printf("%-15s", "Total");
foreach(date:) {
    printf("%10.2f", sum(amount: date));
}
printf("%10.2f\n", sum(amount:));
displaylines();
$ tdb -f exp.f -r exp_cat_date.r exp.d
Tux Family Expenditure Report - 19-Jun-22
--------------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15 08-Dec-15 09-Dec-15 10-Dec-15 11-Dec-15 12-Dec-15 13-Dec-15 14-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- ---------
Entertainment       60.50     85.50    122.00    178.00    130.00  25135.86    138.00                                                                        25849.86
Firearms                                                            1500.00   9500.00             2550.00                                                    13550.00
Air Fare          3000.00             3030.00                       3500.00                                                                                   9530.00
Supplies            91.00     85.50    850.50              219.00                                                                                             1246.00
Bills                        400.50    246.00                        250.50                                                                                    897.00
Clothing           350.50                                            270.50                                                                                    621.00
Fuel                          70.00     70.00     80.00     80.00     90.00     90.00                                                                          480.00
Groceries                                                            439.00                                                                                    439.00
Train Ticket                  10.50     19.20     10.50               10.50               18.60     18.60     18.60     18.60     18.60                        143.70
Coffee               7.00      7.00     14.00      7.00     14.00      7.00      7.00      3.50      3.50      3.50      3.50      3.50      3.50      3.50     87.50
Food                 9.00      9.00     12.50      9.00      9.00                                                                                               48.50
Fun                                                                    3.50     33.40                                                                           36.90
--------------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- ---------
Total             3518.00    668.00   4364.20    284.50    452.00  31206.86   9768.40     22.10   2572.10     22.10     22.10     22.10      3.50      3.50  52929.46
--------------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- --------- ---------
Note the totals are sorted descending. This report output has a column for every date.
Obviously, it would be too wide for normal data (with lots of dates).
To address this issue, tdb in select mode can be used to select only the data of interest.
Expenditure Select File (exp_1_week.s)
select(date >= 20151201 && date <= 20151207);
This is the same report as above, but this time tdb is called twice - first in select
mode (to choose only the required data - 1 week's worth in this example) and that data
is piped to a second tdb instance running in report mode:
$ tdb -f exp.f -s exp_1_week.s exp.d | tdb -f exp.f -r exp_cat_date.r -
Tux Family Expenditure Report - 19-Jun-22
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Entertainment       60.50     85.50    122.00    178.00    130.00  25135.86    138.00  25849.86
Firearms                                                            1500.00   9500.00  11000.00
Air Fare          3000.00             3030.00                       3500.00             9530.00
Supplies            91.00     85.50    850.50              219.00                       1246.00
Bills                        400.50    246.00                        250.50              897.00
Clothing           350.50                                            270.50              621.00
Fuel                          70.00     70.00     80.00     80.00     90.00     90.00    480.00
Groceries                                                            439.00              439.00
Coffee               7.00      7.00     14.00      7.00     14.00      7.00      7.00     63.00
Train Ticket                  10.50     19.20     10.50               10.50               50.70
Food                 9.00      9.00     12.50      9.00      9.00                         48.50
Fun                                                                    3.50     33.40     36.90
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total             3518.00    668.00   4364.20    284.50    452.00  31206.86   9768.40  50261.96
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Again, the category expenditure total column is sorted in descending order. Also note
that in the report above (with all the data), "Train Ticket" was before "Coffee" - but they
have swapped position in this report (because the category totals are different).
Expenditure by Category, Description and Date
This report sorts by the sum of the expenditure based on the descriptions field, ascending -
within each category.
aggregate(category, date, description);
function displaylines() {
    printf("---------------");
    foreach(date:) {
        printf(" ---------");
    }
    printf(" ---------\n", "Total");
}
printf("Tux Family Itemized Expenditure Report - %s\n\n",
        formatdate("%d-%b-%y", reportdate()));
displaylines();
printf("%-15s", "Category");
foreach(date:) {
    printf("%10s", formatdate("%d-%b-%y", date));
}
printf("%10s\n", "Total");
displaylines();
foreach(category:) {
    printf("%-15s\n", category);
sort(description: sum(amount: category, description));
    foreach(description: category) {
        printf("%15s", description);
        foreach(date:) {
            amt = sum(amount: category, date, description);
            if (amt != 0) {
                printf("%10.2f", amt);
            } else {
                printf("%10s", "");
            }
        }
        printf("%10.2f\n", sum(amount: category, description));
    }
    displaylines();
    printf("%15s", "Subtotal");
    foreach(date:) {
        amt = sum(amount: category, date);
        if (amt != 0) {
            printf("%10.2f", amt);
        } else {
            printf("%10s", "");
        }
    }
    printf("%10.2f\n", sum(amount: category));
    displaylines();
    printf("\n");
}
displaylines();
printf("%-15s", "Total");
foreach(date:) {
    printf("%10.2f", sum(amount: date));
}
printf("%10.2f\n", sum(amount:));
displaylines();
$ tdb -f exp.f -s exp_1_week.s exp.d | tdb -f exp.f -r exp_cat_descr_date.r -
Tux Family Itemized Expenditure Report - 19-Jun-22
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Air Fare       
      Las Vegas                        530.00                                            530.00
         Sydney                       2500.00                                           2500.00
    Vladivostok   3000.00                                                               3000.00
      Hong Kong                                                     3500.00             3500.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal   3000.00             3030.00                       3500.00             9530.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Bills          
          Water                        120.50                                            120.50
            Gas                        125.50                                            125.50
        Garbage                                                      250.50              250.50
    Electricity              400.50                                                      400.50
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal              400.50    246.00                        250.50              897.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Clothing       
       Lingerie                                                      270.50              270.50
 Leather Jacket    350.50                                                                350.50
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal    350.50                                            270.50              621.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Coffee         
     Carpe Diem      3.50      3.50      7.00      3.50      7.00      3.50      3.50     31.50
   Morning Java      3.50      3.50      7.00      3.50      7.00      3.50      3.50     31.50
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal      7.00      7.00     14.00      7.00     14.00      7.00      7.00     63.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Entertainment  
          Movie                                   52.00                                   52.00
      Cocktails     60.50                                             62.00              122.50
           Wine               85.50     81.00     83.00     85.00     57.00     89.00    480.50
         Cognac                                                      850.00              850.00
         Cigars                                                     1235.00             1235.00
           Beer                         41.00     43.00     45.00   1491.44     49.00   1669.44
      Strippers                                                     1900.00             1900.00
        Hookers                                                     2400.00             2400.00
 Can't remember                                                     2468.42             2468.42
          Booze                                                     3450.00             3450.00
        Cocaine                                                     3500.00             3500.00
     Restaurant                                                     7722.00             7722.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal     60.50     85.50    122.00    178.00    130.00  25135.86    138.00  25849.86
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Firearms       
       Glock 19                                                     1500.00             1500.00
   RPG Launcher                                                               9500.00   9500.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal                                                     1500.00   9500.00  11000.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Food           
   School snack                          3.50                                              3.50
   School lunch      9.00      9.00      9.00      9.00      9.00                         45.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal      9.00      9.00     12.50      9.00      9.00                         48.50
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Fuel           
    Lamborghini                         70.00               80.00               90.00    240.00
       Maserati               70.00               80.00               90.00              240.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal               70.00     70.00     80.00     80.00     90.00     90.00    480.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Fun            
  Swimming pool                                                        3.50                3.50
    Ice sailing                                                                 33.40     33.40
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal                                                        3.50     33.40     36.90
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Groceries      
         Liquor                                                       49.50               49.50
    Weekly shop                                                      389.50              389.50
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal                                                      439.00              439.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Supplies       
        Pencils      8.50                                                                  8.50
        Crayons                                             10.50                         10.50
          Books     82.50     85.50                                                      168.00
      SSD drive                                            208.50                        208.50
         Laptop                        850.50                                            850.50
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal     91.00     85.50    850.50              219.00                       1246.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Train Ticket   
  Football game                         19.20                                             19.20
         Office               10.50               10.50               10.50               31.50
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
       Subtotal               10.50     19.20     10.50               10.50               50.70
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total             3518.00    668.00   4364.20    284.50    452.00  31206.86   9768.40  50261.96
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Expenditure by Penguin, Category and Date (active dates)
By default (when sort is not used), every field's data is sorted ascending in
alphabetical (for string fields) or numerical (for int and float fields) order.
aggregate(penguin, category, date);
function displaylines() {
    printf("---------------");
    foreach(date: penguin) {
        printf(" ---------");
    }
    printf(" ---------\n", "Total");
}
printf("Tux Family Expenditure By Category Report - %s\n\n",
        formatdate("%d-%b-%y", reportdate()));
foreach(penguin:) {
    printf("\n============== Expenditure for %s ===============\n", penguin);
    displaylines();
    printf("%-15s", "Category");
    foreach(date: penguin) {
        printf("%10s", formatdate("%d-%b-%y", date));
    }
    printf("%10s\n", "Total");
    displaylines();
    foreach(category: penguin) {
        printf("%-15s", category);
        foreach(date: penguin) {
            cat_date_amt = sum(amount: penguin, category, date);
            if (cat_date_amt != 0) {
                printf("%10.2f", cat_date_amt);
            } else {
                printf("%10s", "");
            }
        }
        printf("%10.2f\n", sum(amount: penguin, category));
    }
    displaylines();
    printf("%-15s", "Total");
    foreach(date: penguin) {
        printf("%10.2f", sum(amount: penguin, date));
    }
    printf("%10.2f\n", sum(amount: penguin));
    displaylines();
}
$ tdb -f exp.f -s exp_1_week.s exp.d | tdb -f exp.f -r exp_penguin_cat_act_dates.r -
Tux Family Expenditure By Category Report - 19-Jun-22
============== Expenditure for Tux ===============
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Air Fare          3000.00             2500.00                       3500.00             9000.00
Coffee               3.50      3.50      7.00      3.50      7.00      3.50      3.50     31.50
Entertainment                          122.00    139.00    130.00  24883.36    138.00  25412.36
Firearms                                                            1500.00   9500.00  11000.00
Fuel                          70.00     70.00     80.00     80.00     90.00     90.00    480.00
Train Ticket                  10.50     19.20     10.50               10.50               50.70
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total             3003.50     84.00   2718.20    233.00    217.00  29987.36   9731.50  45974.56
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
============== Expenditure for Tux Jr. ===============
--------------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- ---------
Entertainment                                     13.00                         13.00
Food                 4.50      4.50      8.00      4.50      4.50               26.00
Fun                                                                   33.40     33.40
Supplies            82.50              850.50              219.00             1152.00
--------------- --------- --------- --------- --------- --------- --------- ---------
Total               87.00      4.50    858.50     17.50    223.50     33.40   1224.40
--------------- --------- --------- --------- --------- --------- --------- ---------
============== Expenditure for Tuxette ===============
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Air Fare                               530.00                                            530.00
Bills                        400.50    246.00                        250.50              897.00
Clothing           350.50                                            270.50              621.00
Coffee               3.50      3.50      7.00      3.50      7.00      3.50      3.50     31.50
Entertainment       60.50     85.50               13.00              252.50              411.50
Groceries                                                            439.00              439.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total              414.50    489.50    783.00     16.50      7.00   1216.00      3.50   2930.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
============== Expenditure for Tuxina ===============
--------------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- ---------
Entertainment                                     13.00                         13.00
Food                 4.50      4.50      4.50      4.50      4.50               22.50
Fun                                                                    3.50      3.50
Supplies             8.50     85.50                                             94.00
--------------- --------- --------- --------- --------- --------- --------- ---------
Total               13.00     90.00      4.50     17.50      4.50      3.50    133.00
--------------- --------- --------- --------- --------- --------- --------- ---------
Note that the date columns (in the output above) are not the same for all penguins. While this format
might be useful in some cases, the report output might be more readable if all the dates were displayed
for every penguin. This would require a trivial modification to the above program (see below).
Expenditure by Penguin, Category and Date - Report Source (all dates)
aggregate(penguin, category, date);
function displaylines() {
    printf("---------------");
    foreach(date:) {
        printf(" ---------");
    }
    printf(" ---------\n", "Total");
}
printf("Tux Family Expenditure By Penguin Report - %s\n\n",
        formatdate("%d-%b-%y", reportdate()));
foreach(penguin:) {
    printf("\n============== Expenditure for %s ===============\n", penguin);
    displaylines();
    printf("%-15s", "Category");
    foreach(date:) {
        printf("%10s", formatdate("%d-%b-%y", date));
    }
    printf("%10s\n", "Total");
    displaylines();
    foreach(category: penguin) {
        printf("%-15s", category);
        foreach(date:) {
            cat_date_amt = sum(amount: penguin, category, date);
            if (cat_date_amt != 0) {
                printf("%10.2f", cat_date_amt);
            } else {
                printf("%10s", "");
            }
        }
        printf("%10.2f\n", sum(amount: penguin, category));
    }
    displaylines();
    printf("%-15s", "Total");
    foreach(date:) {
        printf("%10.2f", sum(amount: penguin, date));
    }
    printf("%10.2f\n", sum(amount: penguin));
    displaylines();
}
$ tdb -f exp.f -s exp_1_week.s exp.d | tdb -f exp.f -r exp_penguin_cat_all_dates.r -
Tux Family Expenditure By Penguin Report - 19-Jun-22
============== Expenditure for Tux ===============
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Air Fare          3000.00             2500.00                       3500.00             9000.00
Coffee               3.50      3.50      7.00      3.50      7.00      3.50      3.50     31.50
Entertainment                          122.00    139.00    130.00  24883.36    138.00  25412.36
Firearms                                                            1500.00   9500.00  11000.00
Fuel                          70.00     70.00     80.00     80.00     90.00     90.00    480.00
Train Ticket                  10.50     19.20     10.50               10.50               50.70
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total             3003.50     84.00   2718.20    233.00    217.00  29987.36   9731.50  45974.56
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
============== Expenditure for Tux Jr. ===============
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Entertainment                                     13.00                                   13.00
Food                 4.50      4.50      8.00      4.50      4.50                         26.00
Fun                                                                             33.40     33.40
Supplies            82.50              850.50              219.00                       1152.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total               87.00      4.50    858.50     17.50    223.50      0.00     33.40   1224.40
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
============== Expenditure for Tuxette ===============
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Air Fare                               530.00                                            530.00
Bills                        400.50    246.00                        250.50              897.00
Clothing           350.50                                            270.50              621.00
Coffee               3.50      3.50      7.00      3.50      7.00      3.50      3.50     31.50
Entertainment       60.50     85.50               13.00              252.50              411.50
Groceries                                                            439.00              439.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total              414.50    489.50    783.00     16.50      7.00   1216.00      3.50   2930.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
============== Expenditure for Tuxina ===============
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Category        01-Dec-15 02-Dec-15 03-Dec-15 04-Dec-15 05-Dec-15 06-Dec-15 07-Dec-15     Total
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Entertainment                                     13.00                                   13.00
Food                 4.50      4.50      4.50      4.50      4.50                         22.50
Fun                                                                    3.50                3.50
Supplies             8.50     85.50                                                       94.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Total               13.00     90.00      4.50     17.50      4.50      3.50      0.00    133.00
--------------- --------- --------- --------- --------- --------- --------- --------- ---------
Now all penguins have the same dates. Some "cells" are empty, but this output is more
readable.
Some Other Very Useful Features - Grocery Store Prices
Grocery Fields File (gro.f)
string  chain           #  Franklin's
string  location        #  Pennant Hills
string  item            #  beer    coke    bananas    cereal
float   price           #  8.00   48.00       3.95     3.55
int     quantity        #     6      24          1        1
float   size            # 0.375   1.125        1.0    500.0
string  unit            #    ml      ml         kg        g
Comments in the fields file.
Grocery Data File (gro.d)
Coles                   "Los Angeles"   "Apples, Granny Smith"   5.50    1      1.0     kg
Coles                   "Chicago"       "Apples, Granny Smith"   4.00    1      1.0     kg
Woolworths              "Sydney"        "Apples, Granny Smith"   6.00    1      1.0     kg
Woolworths              "Tokyo"         "Apples, Granny Smith"   9.00    1      0.5     kg
Coles                   "Sydney"        "Bananas"                4.00    1      1.0     bag # sale price
Coles                   "Sydney"        "Bananas"                5.00    2      1.0     bag # regular price
Woolworths              "Tokyo"         "Bananas"                9.00    3      0.5     bag
Coles                   "Sydney"        "Bananas"                5.00    1      1.0     kg
Coles                   "Tokyo"         "Bananas"                6.00    1      1.0     kg
Woolworths              "Los Angeles"   "Bananas"                4.00    1      1.0     kg
Woolworths              "Chicago"       "Bananas"                4.00    1      1.0     kg
"Raju's Corner Shop"    "London"        "Bananas"                8.00    1      0.5     kg
Coles                   "Sydney"        "Beer, VB"              13.00    6      0.375   l # first time
Coles                   "Sydney"        "Beer, VB"              13.50    6      0.375   l # second time
Coles                   "Sydney"        "Beer, VB"              14.00    6      0.375   l # third time
Coles                   "Adelaide"      "Beer, VB"              15.75    6      0.375   l
Woolworths              "Sydney"        "Beer, VB"              45.00   24      0.375   l
Woolworths              "Adelaide"      "Beer, VB"              49.50   24      0.375   l
Coles                   "Toronto"       "Beer, Molson Golden"   32.74   24      0.341   l
Woolworths              "Toronto"       "Beer, Molson Golden"   36.83   24      0.341   l
Coles                   "Montreal"      "Beer, Molson Golden"   40.92   24      0.341   l
Woolworths              "Montreal"      "Beer, Molson Golden"   45.01   24      0.341   l
Note that there can also be comments in the data files, blank lines are ignored,
and the same item has occasionally been purchased from the same "store".
The new field "store" is is created by concatenating the chain and location fields (see below).
Also, the data need not be aligned (as it is in these example data files); it must be separated by "white space".
Grocery Report Source
join(string store: chain, ", ", location);
join(string item_unit: item, " ($/", unit, ")");
aggregate(store, item_unit, price, quantity, size);
#include "gro.i"
foreach(store:)
    tot_cost[store] = 0.0;      /* must be a float */
foreach(item_unit:) {
    tot_price = 0.0; tot_spend = 0.0; unnecessary_array_a[item_unit] = 0;
    foreach(store: item_unit) {
        tot_store_price = 0.0; tot_store_spend = 0.0;
        foreach(price: item_unit, store) {
            foreach(quantity: item_unit, store, price) {
                foreach(size: item_unit, store, price, quantity) {
                    c = count(size, quantity, price, item_unit, store);
                    tot_store_price += c * price;
                    tot_store_spend += c * quantity * size;
                }
            }
        }
        tot_cost[store] = tot_store_price/tot_store_spend;
        tot_price += tot_store_price;
        tot_spend += tot_store_spend;
        n = count(item_unit, store);
        unnecessary_array_a[item_unit] += n;
        unnecessary_multi_array_b[item_unit, store, "ridiculous", "indexes"] = n;
    }
    printf("%s\n", item_unit);
    sort(store: tot_cost[store]);
    foreach(store: item_unit) {
        printf(" %-33s%8.2f%9d\n", store, tot_cost[store],
            unnecessary_multi_array_b[item_unit, store, "ridiculous", "indexes"]);
    }
    printf(" %33s%8.2f%9d\n", "Weighted average", tot_price/tot_spend,
                                    unnecessary_array_a[item_unit]);
    printf("\n");
}
Using the join statement to effectively create new fields from the original ones can be
particularly useful - as in this example.
This report also makes use of some other features that are (in this report) egregiously
unnecessary. In particular, the use of the #include and multi-dimensional arrays
could very easily have been avoided.
Grocery Report Include File (gro.i)
printf("                                  Avg Unit   Number\n");
printf("Store                             Price      Purch\n");
printf("==============================    ========   ======\n");
Grocery Report Output
$ tdb -f gro.f -r gro.r gro.d
                                  Avg Unit   Number
Store                             Price      Purch
==============================    ========   ======
Apples, Granny Smith ($/kg)
 Coles, Chicago                       4.00        1
 Coles, Los Angeles                   5.50        1
 Woolworths, Sydney                   6.00        1
 Woolworths, Tokyo                   18.00        1
                  Weighted average    7.00        4
Bananas ($/bag)
 Coles, Sydney                        3.00        2
 Woolworths, Tokyo                    6.00        1
                  Weighted average    4.00        3
Bananas ($/kg)
 Woolworths, Chicago                  4.00        1
 Woolworths, Los Angeles              4.00        1
 Coles, Sydney                        5.00        1
 Coles, Tokyo                         6.00        1
 Raju's Corner Shop, London          16.00        1
                  Weighted average    6.00        5
Beer, Molson Golden ($/l)
 Coles, Toronto                       4.00        1
 Woolworths, Toronto                  4.50        1
 Coles, Montreal                      5.00        1
 Woolworths, Montreal                 5.50        1
                  Weighted average    4.75        4
Beer, VB ($/l)
 Woolworths, Sydney                   5.00        1
 Woolworths, Adelaide                 5.50        1
 Coles, Sydney                        6.00        3
 Coles, Adelaide                      7.00        1
                  Weighted average    5.58        6
Please refer to the 
tdb Users' Guide for more info.
Based entirely on the particularly speculative and overwhelmingly circumstantial evidence above,
Tux may have thrown an outraaaaaaaaaaaageous party in Hong Kong on 6 Dec!
(But, as we know, what happens on the road stays on the road.)