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.)