Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jbrown123/b65004fd4e8327748b650c77383bf553 to your computer and use it in GitHub Desktop.
Save jbrown123/b65004fd4e8327748b650c77383bf553 to your computer and use it in GitHub Desktop.
Creating arbitrary-depth recursive queries in SQLITE (works for any SQL compliant system) using CTEs (common table expressions)

Recursive Queries Using Common Table Expressions

Common Table Expressions (CTEs) are a bit complex and difficult to understand at first blush. Many of the tutorials and examples on the net don't make it any easier for those just starting out. I thought I'd put together a quick gist that tries to simplify the concept and demonstrate how to do recursive queries using CTEs.

Keep in mind that CTEs have other uses besides just recursive queries but this gist is just about how they can be used to create recursive searches.

I'm using SQLite in this example but any SQL language that implements the WITH keyword should be able to do the same thing. If you've never used SQLite before, you are missing out on an amazing, open source, stand alone, SQL engine. I encourage you to check it out.

A practical example

In the sample data we have a basic employee directory. The first column is the users name. The second column is their user ID, the third is their title, and the last column is the user ID of their manager. This creates a simple flat file database that encapsulates hierarchical data. In this case, the management structure of the company. You can find anyone's position in the company by simply following the chain of managers until you reach the top (a person with no manager listed).

First, of course, download the files from the gist to a directory.

Use the initialization.sql file to create the table and import the data as follows:

sqlite3 test.sqlite < initialization.sql

Now you can access the data via either the users table or via the view created using the CTE. The CTE allows you to do an arbitrary depth recursive scan of the data to create a management chain or path back to the top of the organization.

Query the users table

sqlite> select * from users order by name limit 10;
Adelina Marsha|admarsha|Change Magician|shcarroll
Akilah Audie|akaudie|Retail Jedi|hetennille
Alena Patrick|alpatrick|New Media Guru|auandrea
Alisia Caterina|alcaterina|Happiness Advocate|suhobert
Allen Cory|alcory|Digital Overlord|chleopoldo
Alphonso Fredrick|alfredrick|Director of First Impressions|wamitch
Amos Chia|amchia|Digital prophet|dehong
Angelic Arline|anarline|Under Secretary to the Sub-Committee|tacathie
Angie Cecilia|ancecilia|Cheese Sprayer|alcory
Anika Rob|anrob|Ambassador of buzz|debertie

This is just the stock query you can do of any table. The last field is the manager user ID (UID) so all we can see is the UID of the users's manager. We could write a query to see the manager's name instead of just their UID by JOINing our current query with the same table using the manager UID. For example

sqlite> select u.*,m.name from users u join users m on u.manager=m.cn order by u.name limit 10;
Adelina Marsha|admarsha|Change Magician|shcarroll|Shanita Carroll
Akilah Audie|akaudie|Retail Jedi|hetennille|Hermine Tennille
Alena Patrick|alpatrick|New Media Guru|auandrea|Audria Andrea
Alisia Caterina|alcaterina|Happiness Advocate|suhobert|Sulema Hobert
Allen Cory|alcory|Digital Overlord|chleopoldo|Ching Leopoldo
Alphonso Fredrick|alfredrick|Director of First Impressions|wamitch|Wava Mitch
Amos Chia|amchia|Digital prophet|dehong|Dee Hong
Angelic Arline|anarline|Under Secretary to the Sub-Committee|tacathie|Tajuana Cathie
Angie Cecilia|ancecilia|Cheese Sprayer|alcory|Allen Cory
Anika Rob|anrob|Ambassador of buzz|debertie|Dedra Bertie

We could continue this process to see the next manager up the chain as well by using a subquery. However, the query will get more and more complex and, without examining the data, we don't really know how many subqueries we need to add to be sure we get all the way to the top of the tree.

Query using the CTE view

However by using our recursive CTE we can get a complete list of the management chain, all the way to the top of the tree. Using our recursive CTE we get the following

sqlite> select * from bp order by name limit 10;
Adelina Marsha|admarsha|Change Magician|shcarroll|Shanita Carroll > Ching Leopoldo
Akilah Audie|akaudie|Retail Jedi|hetennille|Hermine Tennille > Allen Cory > Ching Leopoldo
Alena Patrick|alpatrick|New Media Guru|auandrea|Audria Andrea > Helena Darius > Ching Leopoldo
Alisia Caterina|alcaterina|Happiness Advocate|suhobert|Sulema Hobert > Helena Darius > Ching Leopoldo
Allen Cory|alcory|Digital Overlord|chleopoldo|Ching Leopoldo
Alphonso Fredrick|alfredrick|Director of First Impressions|wamitch|Wava Mitch > Ching Leopoldo
Amos Chia|amchia|Digital prophet|dehong|Dee Hong > Taylor Harvey > Ching Leopoldo
Angelic Arline|anarline|Under Secretary to the Sub-Committee|tacathie|Tajuana Cathie > Helena Darius > Ching Leopoldo
Angie Cecilia|ancecilia|Cheese Sprayer|alcory|Allen Cory > Ching Leopoldo
Anika Rob|anrob|Ambassador of buzz|debertie|Dedra Bertie > Wava Mitch > Ching Leopoldo

As we can see Allen Cory reports directly to the top boss (Ching Leopoldo). Alphonso Fredrick reports to Wava Mitch who reports to Ching. Alena Patrick reports to Audria, and Alisia Caterina reports to Sulema. Both Audria and Sulema report to Helena who then reports to Ching.

As you can see, there are a number of different levels of reports in the company. Some report directly to the boss, while others are two or more levels away from the boss. It would be nearly impossible to create a sufficiently deep set of joins to create the 'boss path' back to the root of the organization. And even if you did, it would be very fragile and need constant maintenance to keep up with a growing organization.

On the other hand, by using a recursive CTE, we are able to handle any level of recursion (up to the limits of the server's recursion setting).

Anatomy of the CTE

Creating a view in SQLite give us an easy way to store our CTE in the database so we don't have to type all that out each time we want to return the management path in a query. Now, instead of specifying the users table, we instead specify the view name (bp). The view works just like a real table except that you can't insert into a view.

So how does all the recursive magic happen? Let's take a look at the body of the view using the recursive common table expression.

CREATE VIEW bp AS
    -- create a CTE (common table expression)
    -- think of this as creating a temporary table that only exists during this query
    -- works somewhat like CREATE TEMPORARY TABLE bosspath(cn, path)
    WITH RECURSIVE bosspath(cn,path) AS
    (
        -- initial select statement to get started
        -- this is only executed once
        -- in this case we are starting at the 'root' of the management tree
        --   the record with no manager
        SELECT cn,name FROM users WHERE manager=''

        -- merge those results with the following query
        UNION ALL

        -- recursive select statement
        -- executed repeatedly until there are no more results
        SELECT users.cn,users.name||' > '||bosspath.path
            FROM users
            JOIN bosspath ON users.manager=bosspath.cn
    )

    -- now query the CTE to produce results
    -- think of 'bosspath' as being a (very) temporary table
    SELECT users.*,bosspath.path FROM users JOIN bosspath ON users.manager=bosspath.cn;

As you can see from the embedded comments (lines with "--"), the CTE starts off using the 'WITH RECURSIVE' keywords. Next we have the name of the CTE (bosspath) followed by the columns (cn, and path) that this CTE returns. Think of it as defining a (very temporary) table named bosspath with two columns, 'cn' and 'path'. Following this is the body of the CTE which will be discussed in some detail below. And finally there is the main SELECT statement that returns results. Note that in the SELECT we are joining data from the main users table with data from the CTE to create our final result.

Recursive CTE components

Within a recursive CTE there are two major components. The first is an initialization query to get the ball rolling. The second is the recursive query that will be called repeatedly.

The initialization query must return at least one result, but it can return more. Each of those results goes on a queue to be fed into the recursive query until no new results are returned.

The recursive query (the one after UNION ALL) is the real workhorse of the recursive CTE. This query is executed on everything in the queue and all rows output go on that same queue to be further processed by the same query. That's where the recursive magic comes in.

Note in particular how we build up the path using concatenation of the previous results with the current name. This is what allows the query to return the full management chain as a single value / column (see below for a discussion of how to reverse the order).

At the bottom we finally have a query against the CTE we've constructed. This works just like a normal query against a table and you can include joins, limits, and pretty much any other normal SQL constructs.

Reversing the order of the management chain

We can easily reverse the order of the boss list (going from top down instead of bottom up) by reversing the order that we paste the string together in the recursive query. Instead of

SELECT users.cn,users.name||' > '||bosspath.path

we use

SELECT users.cn,bosspath.path||' > '||users.name

so that the previous path comes first, followed by the current user (manager) name.

Easily find everyone under any manager

Another advantage of building the management chain path as a string is searching for everyone under a particular manager. Because the CTE acts as a temporary table, and since we created the management path as a single string using concatenation, we can now perform queries on the path itself.

For example, if we want to see everyone who reports up through Allen Cory, we can do a query like this.

sqlite> SELECT * FROM bp WHERE path like '%Allen Cory%' order by name limit 10;
Akilah Audie|akaudie|Retail Jedi|hetennille|Hermine Tennille > Allen Cory > Ching Leopoldo
Angie Cecilia|ancecilia|Cheese Sprayer|alcory|Allen Cory > Ching Leopoldo
Ashly Farah|asfarah|Chief Inspiration Officer|hetennille|Hermine Tennille > Allen Cory > Ching Leopoldo
Dewayne Darius|dedarius|Chief Inspiration Officer|hetennille|Hermine Tennille > Allen Cory > Ching Leopoldo
Dot Molly|domolly|Oyster Floater|mamaurice|Mabelle Maurice > Gina Brook > Allen Cory > Ching Leopoldo
Gina Brook|gibrook|Problem Wrangler|alcory|Allen Cory > Ching Leopoldo
Hermine Tennille|hetennille|New Media Guru|alcory|Allen Cory > Ching Leopoldo
Jone Kenna|jokenna|Oyster Floater|alcory|Allen Cory > Ching Leopoldo
Kary Lin|kalin|Director of First Impressions|gibrook|Gina Brook > Allen Cory > Ching Leopoldo
Laurena Leone|laleone|Beverage Dissemination Officer|hetennille|Hermine Tennille > Allen Cory > Ching Leopoldo

We can also use all the normal aggregation tools, such as COUNT, on our CTE based view.

sqlite> SELECT COUNT(*) FROM bp WHERE path like '%Allen Cory%';
27

Conclusion

A CTE is easily understood if you think of it as just creating a temporary table, with the specified fields, that only lasts for the duration of the query. Recursive CTEs give us a way to express in pure SQL what would normally be done in an external programming language (search for a person then recursively search for the manager up the chain). By expressing and returning the recursive data as a string, we can do further queries on the recursive data that would be nearly impossible to do in SQL any other way (e.g. find everyone who reports up through a given person).

Hopefully this has given you a better understanding of how recursive CTEs work and how they might be helpful in projects involving hierarchical information.

DROP TABLE IF EXISTS users;
DROP VIEW IF EXISTS bp;
CREATE TABLE users (name, cn, title, manager);
CREATE VIEW bp AS
-- create a CTE (common table expression)
-- think of this as creating a temporary table that only exists during this query
-- works somewhat like CREATE TEMPORARY TABLE bosspath(cn, path)
WITH RECURSIVE bosspath(cn,path) AS
(
-- initial select statement to get started
-- this is only executed once
-- in this case we are starting at the 'root' of the management tree
-- the record with no manager
SELECT cn,name FROM users WHERE manager=''
-- merge those results with the following query
UNION ALL
-- recursive select statement
-- executed repeatedly until there are no more results
SELECT users.cn,users.name||' > '||bosspath.path
FROM users
JOIN bosspath ON users.manager=bosspath.cn
)
-- now query the CTE to produce results
-- think of 'bosspath' as being a (very) temporary table
SELECT users.*,bosspath.path FROM users JOIN bosspath ON users.manager=bosspath.cn;
.mode csv
.import sampledata.csv users
Ching Leopoldo chleopoldo Grand Master of Underlings
Callie Kristen cakristen Oyster Floater jesun
Sabra Rickie sarickie Sous chef cojosue
Shaneka Felice shfelice Chief Inspiration Officer huervin
Audria Andrea auandrea Digital Dynamo hedarius
Celsa Noble cenoble Initiative Officer cojosue
Madeline Christiana machristiana Director of Ethical Hacking diaudrey
Richard Ralph riralph Sales Ninja sasusana
Marcy Blanche mablanche Director of First Impressions jesun
Cliff Sue clsue Director of First Impressions vachris
Shanita Carroll shcarroll Personalized care assistant chleopoldo
Dedra Bertie debertie Animal Colourist wamitch
Ursula Ellen urellen Digital prophet joalex
Dean Jame dejame Marketing Rock star rukay
Dot Molly domolly Oyster Floater mamaurice
Cris Dorian crdorian Chief Amazement Officer majordon
Eli Bella elbella Director of First Impressions suhobert
Tyrell Shan tyshan Under Secretary to the Sub-Committee joalex
Bunny Lavette bulavette Animal Colourist nomichell
Sarina Susana sasusana Space Travel Agent huervin
Stanton Toby sttoby Crayon Evangelist chlady
Ginette Verna giverna Grand Master of Underlings tacathie
Lakenya Marlin lamarlin Chief Inspiration Officer tamandi
Timmy Seymour tiseymour Actions and Repercussions Adviser luferdinand
Elwood Barb elbarb Hyphenated-specialist majordon
Rosa Jamie rojamie Marketing Rock star debertie
Gracie Aubrey graubrey Chief Chatter jesun
Kesha Roberto keroberto Sales Ninja rukay
Danita Basil dabasil Senior Kindle Evangelist shcarroll
Doris Ruth doruth Sous chef rukay
Taryn Mackenzie tamackenzie Associate Vice President mamaurice
Santa Scott sascott Actions and Repercussions Adviser tonorma
Laveta Rolando larolando Under Secretary to the Sub-Committee anrob
Elias Easter eleaster Creativity Analyst tacathie
Eura Sabine eusabine Twisted Brother tonorma
Callie Hai cahai Under Secretary to the Sub-Committee yolester
Shanell Maggie shmaggie Digital Dynamo tamandi
Frederic Luke frluke Problem Wrangler marupert
Collene Josue cojosue Twisted Brother huervin
Carter Hollis cahollis Animal Colourist alfredrick
Miguel Xiao mixiao Creativity Analyst majordon
Fredricka Emerald fremerald Retail Jedi tacathie
Delphia Foster defoster Part-Time Czar tonorma
Klara Lai kllai Patron Saint of Academic Studying chlady
Amos Chia amchia Digital prophet dehong
Kisha Andera kiandera Chief Chatter auandrea
Myles Martine mymartine Wizard of Light Bulb Moments rukay
Margie Catalina macatalina Space Travel Agent alfredrick
Marylou Molly mamolly Digital Overlord rukay
Jesenia May jemay Pneumatic device and machine optimizer tonorma
Tanya Major tamajor Sous chef elstefani
Heide Wilburn hewilburn Chief curator shfelice
Iola Edie ioedie Sous chef majordon
Sabra Anderson saanderson Professionalist International and world-wide optical and vision-focused tenured professorship gibrook
Cathy Pam capam Master Handshaker auandrea
Bo Jarrett bojarrett Digital Dynamo huervin
Florrie Merideth flmerideth Conversation Architect jesun
Lucrecia Florence luflorence Light Bender chlady
Williemae Vicente wivicente Patron Saint of Academic Studying hetennille
Micki Hester mihester Beverage Dissemination Officer sasusana
Antony Jordon anjordon Hyphenated-specialist dehong
Dewayne Darius dedarius Chief Inspiration Officer hetennille
Osvaldo Julio osjulio Director of Ethical Hacking chlady
Berniece Ernesto beernesto Chief curator auandrea
Eliseo Emma elemma Crayon Evangelist chleopoldo
Truman January trjanuary Marketing Rock star hedarius
Leif Somer lesomer Associate Vice President tacathie
Damian Bonny dabonny Animal Colourist majordon
Cicely Hazel cihazel Beverage Dissemination Officer rukay
Angie Cecilia ancecilia Cheese Sprayer alcory
Madge Rupert marupert Part-Time Czar sasusana
Leatrice Scott lescott Conversation Architect alfredrick
Lavern Shelly lashelly Problem Wrangler luferdinand
Azucena Heidi azheidi Director of First Impressions laelsa
Mary Emanuel maemanuel Part-Time Czar tacathie
Carmel Brenton cabrenton Creator of opportunities cahai
Cherish Marian chmarian The Resinator caamparo
Graig Lauri grlauri Chief curator suhobert
Danial Marry damarry Direct Mail Demi-God jetim
Kaitlin Stacey kastacey Personalized care assistant marupert
Hermine Tennille hetennille New Media Guru alcory
Lu Ferdinand luferdinand Associate to the Executive Manager of Marketeering and Conservation efforts hetennille
Georgina Sidney gesidney Director of First Impressions huervin
Kimberly Lawrence kilawrence Oyster Floater debertie
Denna Denise dedenise Crayon Evangelist jolong
Man Tracy matracy Part-Time Czar jebroderick
Sari Sun sasun Space Travel Agent rukay
Lanette Thao lathao Oyster Floater shfelice
Vernell Farrah vefarrah Master Handshaker mcdan
Elena Whitley elwhitley Chief Biscuit Dunker jesun
Humberto Kip hukip Senior Kindle Evangelist alfredrick
Drucilla Ida drida Creator of opportunities suhobert
Demetrice Chester dechester Cheese Sprayer jesun
Venessa Deanne vedeanne Ambassador of buzz suhobert
Valrie Chris vachris Personalized care assistant elstefani
Dudley Kala dukala Director of Fun cahai
Jeanette Clinton jeclinton Space Travel Agent shcarroll
Jackqueline Walker jawalker Director of Ethical Hacking suhobert
Kaleigh Tracy katracy Direct Mail Demi-God arwilson
Darrel Gordon dagordon Hyphenated-specialist lathao
Jettie Dennis jedennis Master Handshaker shmargaret
Emiko Francisco emfrancisco Happiness Advocate vachris
Wava Mitch wamitch Wizard of Light Bulb Moments chleopoldo
Laurie Sonia lasonia Catalyst tacathie
Treasa Burton trburton Creativity Analyst cojosue
Blossom Elton blelton Arts and Crafts Designer flpatricia
Anjelica Tena antena Catalyst cojosue
Donna Jamal dojamal Accounting Ninja jetim
Ralph Jacquelin rajacquelin Creativity Analyst cahai
Latanya Armand laarmand Patron Saint of Academic Studying jetim
Sigrid Newton sinewton Creator of Happiness cojosue
Lynwood Ora lyora Social Media Trailblazer yolester
Magaly Chase machase Communications Ambassador shfelice
Letitia Jayme lejayme New Media Guru alfredrick
Hildred Isabella hiisabella Pneumatic device and machine optimizer vachris
Justine Chuck juchuck Master Handshaker chlady
Jong Alex joalex Creator of opportunities wamitch
Mitsuko Song misong Catalyst dehong
Helena Darius hedarius Marketing Rock star chleopoldo
Margarito Chan machan Chief Amazement Officer dehong
Alphonso Fredrick alfredrick Director of First Impressions wamitch
Hunter Ervin huervin Sous chef jetim
Hermine Afton heafton Creator of opportunities cahai
Dave Leon daleon Twisted Brother cahai
Bradford Dominque brdominque Marketing Rock star dehong
Allen Cory alcory Digital Overlord chleopoldo
Shaina Houston shhouston Chief Amazement Officer majordon
Tenesha Santana tesantana Conversation Architect auandrea
Fernanda Merle femerle Director of First Impressions suhobert
Laurena Leone laleone Beverage Dissemination Officer hetennille
Sherlyn Wilmer shwilmer Actions and Repercussions Adviser mamaurice
Danielle Lavelle dalavelle Catalyst cojosue
Teisha Lee telee Wizard of Light Bulb Moments suhobert
Janie Celeste jaceleste Sous chef flpatricia
Jamel Hilario jahilario Project Meanie majordon
Ashly Farah asfarah Chief Inspiration Officer hetennille
Shirleen Brain shbrain Cheese Sprayer cojosue
May Daria madaria Head of global trends and futuring mcdan
Christin Jerry chjerry Communications Ambassador jebroderick
Ronda Lana rolana Communications Ambassador alcory
Bertie Rupert berupert Director of First Impressions nomichell
Iona Virgilio iovirgilio Project Meanie stfay
Corene Pablo copablo Brand Evangelist dojamal
Tomika Norma tonorma Creativity Analyst dojamal
Selene Maile semaile Beverage Dissemination Officer alcory
Adelina Marsha admarsha Change Magician shcarroll
Sarai Ashton saashton Project Meanie jesun
Lizette Hilde lihilde Conversation Architect alfredrick
Jesica Chae jechae Chief Chatter suhobert
Robbin Daisy rodaisy Digital Dynamo rukay
Janetta Clair jaclair Actions and Repercussions Adviser jesun
Jennine Tim jetim Beverage Dissemination Officer chleopoldo
Milford Anna mianna Director of First Impressions suhobert
Jewel Sung jesung Initiative Officer flpatricia
Florinda Julian fljulian Creator of opportunities auandrea
Keesha Kaye kekaye Professionalist International and world-wide optical and vision-focused tenured professorship alfredrick
Genesis Dale gedale Pneumatic device and machine optimizer alfredrick
Jenette Lucien jelucien Chief Amazement Officer mcdan
Janine Kendra jakendra Grand Master of Underlings yolester
Noelle Edmund noedmund Digital prophet alfredrick
Arnette Yee aryee Part-Time Czar dojamal
Clorinda Emmett clemmett Director of Fun tonorma
Voncile Joesph vojoesph Crayon Evangelist cahai
Callie Houston cahouston Actions and Repercussions Adviser jesun
Sulema Hobert suhobert Direct Mail Demi-God hedarius
Shanell Fausto shfausto Sous chef marupert
Sena Karin sekarin Pneumatic device and machine optimizer alcory
Freda Albert fralbert Change Magician wamitch
Alisia Caterina alcaterina Happiness Advocate suhobert
Omega Jeannette omjeannette Accounting Ninja mcdan
Taylor Harvey taharvey Digital prophet chleopoldo
Suzy Verona suverona Second Tier Totalist jesun
Santos Estrella saestrella Conversation Architect arwilson
Paulita Cesar pacesar Happiness Advocate caamparo
Alena Patrick alpatrick New Media Guru auandrea
Fredda Christin frchristin Digital prophet jolong
Darwin Adan daadan Communications Ambassador yolester
Mabelle Maurice mamaurice Chief Biscuit Dunker gibrook
Arvilla Wilson arwilson Grand Master of Underlings dojamal
Christa Genia chgenia Marketing Rock star tacathie
Buddy Wilbur buwilbur Twisted Brother dojamal
Sana Ronda saronda Second Tier Totalist rukay
Lelah Lillie lelillie Catalyst drida
Elden Stefani elstefani Conversation Architect chleopoldo
Mireille Janey mijaney Happiness Advocate anrob
Franchesca Roselle frroselle Cheese Sprayer majordon
See Winter sewinter New Media Guru hukip
Akilah Audie akaudie Retail Jedi hetennille
Markita Parker maparker Director of First Impressions alcory
Mina Ramiro miramiro Problem Wrangler huervin
Francene Savannah frsavannah Accounting Ninja alfredrick
Herta Jong hejong Happiness Advocate suhobert
Cordia Cary cocary Beverage Dissemination Officer joalex
Asha Gaston asgaston Professionalist International and world-wide optical and vision-focused tenured professorship suhobert
Cleopatra Serena clserena Associate to the Executive Manager of Marketeering and Conservation efforts tacathie
Tonda Joel tojoel Chief Amazement Officer jesun
Twana Wanda twwanda Pneumatic device and machine optimizer diaudrey
Bert Asuncion beasuncion Actions and Repercussions Adviser alfredrick
Riley Christine richristine Corporate Magician debertie
Roberto Kirsten rokirsten Under Secretary to the Sub-Committee dojamal
Kum Lona kulona Communications Ambassador laelsa
Jerica Everette jeeverette Chief curator majordon
Deandre Anibal deanibal Chief Inspiration Officer ozrich
Courtney Issac coissac Conversation Architect laelsa
Tiffaney Celeste ticeleste Marketing Rock star mamaurice
Chun Edris chedris Retail Jedi hukip
Elroy Jesse eljesse Patron Saint of Academic Studying joalex
Stefania Min stmin Part-Time Czar gewillis
Carla Edmund caedmund Digital Dynamo diaudrey
Leeann Jamel lejamel Digital Overlord joalex
Stefan Abram stabram Light Bender dehong
Noel Michell nomichell Personalized care assistant taharvey
Dannie Dina dadina New Media Guru rukay
Latisha Joyce lajoyce Associate to the Executive Manager of Marketeering and Conservation efforts debertie
Gabriel Paulette gapaulette Light Bender joalex
Rashad Jennie rajennie Marketing Rock star dojamal
Maryjo Chandra machandra Animal Colourist suhobert
Jeannie Sun jesun Senior Kindle Evangelist taharvey
Tawana Tracy tatracy Genius dehong
Floyd Patricia flpatricia Chief Cheerleader jetim
Danilo Sebastian dasebastian Part-Time Czar tacathie
Eulalia Lyle eulyle Sous chef alfredrick
Gina Brook gibrook Problem Wrangler alcory
Carolin Gail cagail Cheese Sprayer majordon
Claribel Willette clwillette Change Magician mcdan
Randa Caroll racaroll Digital prophet cahai
Nana Pam napam Master Handshaker huervin
Dee Hong dehong Associate Vice President taharvey
Yoshiko Lester yolester Genius hedarius
Ruthie Kay rukay Arts and Crafts Designer hedarius
Kittie Lyndon kilyndon Actions and Repercussions Adviser diaudrey
Dianna John dijohn Digital Dynamo shcarroll
Roderick Art roart Creator of Happiness majordon
Salina Alphonso saalphonso Sales Ninja alfredrick
Marisela Oscar maoscar Ambassador of buzz shcarroll
Angelic Arline anarline Under Secretary to the Sub-Committee tacathie
Viviana Jennette vijennette Creator of opportunities arwilson
Ted Valorie tevalorie Second Tier Totalist rukay
Clora Salvatore clsalvatore Marketing Rock star yolester
Diedra Audrey diaudrey Master Handshaker yolester
Nelson Raymond neraymond Director of First Impressions yolester
Joye Long jolong Wizard of Light Bulb Moments tacathie
Kerstin Clark keclark Associate Vice President majordon
Bell Shea beshea Digital Overlord shmargaret
Marleen Ernest maernest Twisted Brother sasusana
Carin Amparo caamparo Light Bender auandrea
Ginger Juan gijuan Digital Dynamo vachris
Shaquita Hugo shhugo Dream Alchemist jebroderick
Jonna Patience jopatience Digital prophet tonorma
Roscoe Angela roangela Dream Alchemist chleopoldo
Machelle Verdell maverdell Chief Inspiration Officer gewillis
Macy Sabina masabina Problem Wrangler huervin
Yolanda Keri yokeri Wizard of Light Bulb Moments tonorma
Margurite Devon madevon Head of global trends and futuring rukay
Mitchel Rupert mirupert Crayon Evangelist hedarius
Renay Maryland remaryland Digital prophet joalex
Julian Karen jukaren Direct Mail Demi-God jebroderick
Terence Dexter tedexter Light Bender nosherry
Linh Clement liclement Part-Time Czar nomichell
Dusti Emmanuel duemmanuel Associate to the Executive Manager of Marketeering and Conservation efforts suhobert
Woodrow Milly womilly Chief Biscuit Dunker luferdinand
Arnulfo Sunshine arsunshine Sous chef elstefani
Santiago Beth sabeth Change Magician jetim
Roselle Blondell roblondell Accounting Ninja elstefani
Ghislaine Marietta ghmarietta Genius tacathie
Lashawnda Elsa laelsa Under Secretary to the Sub-Committee caamparo
Sofia Stewart sostewart Hair Boiler jetim
Anika Rob anrob Ambassador of buzz debertie
Miki Han mihan Hyphenated-specialist majordon
Kitty Tyson kityson Director of First Impressions debertie
Iola Milly iomilly Digital Overlord yolester
Tajuana Cathie tacathie Animal Colourist hedarius
Bertram Rachell berachell The Resinator jebroderick
Geralyn Willis gewillis Direct Mail Demi-God arwilson
Gwyn Matthew gwmatthew Sales Ninja cojosue
Tashia Mandi tamandi Ambassador of buzz nomichell
Parker Shawnee pashawnee Associate to the Executive Manager of Marketeering and Conservation efforts taharvey
Yaeko Carie yacarie Dream Alchemist yolester
Rashida Ka raka Happiness Advocate iomilly
Cris Sun crsun Master Handshaker cahai
Larisa Lily lalily Chief Amazement Officer dojamal
Nerissa Maud nemaud Digital Dynamo hetennille
Buster Arnold buarnold Sous chef hedarius
Mckinley Dan mcdan Problem Wrangler debertie
Henrietta Jacinto hejacinto Part-Time Czar jesun
Cassi Eve caeve Light Bender rukay
Melida Jong mejong Under Secretary to the Sub-Committee shfelice
Grayce Jaime grjaime Part-Time Czar debertie
Fonda Reed foreed Accounting Ninja dehong
Kellee Napoleon kenapoleon Genius huervin
Lindsay Becky libecky Direct Mail Demi-God suhobert
Arden Rudolf arrudolf Professionalist International and world-wide optical and vision-focused tenured professorship elstefani
Tajuana Fidel tafidel Sous chef dehong
Vernie Lloyd velloyd Twisted Brother saestrella
Mark Jame majame Master Handshaker wamitch
Idell Jordon idjordon Under Secretary to the Sub-Committee laarmand
Marnie Rudolph marudolph Master Handshaker hedarius
Kary Lin kalin Director of First Impressions gibrook
Jose Robbie jorobbie VP of Misc. Stuff jetim
Carroll Shayne cashayne Marketing Rock star yolester
Noreen Sherry nosherry Grand Master of Underlings dehong
Tammy Amos taamos Director of First Impressions tacathie
Stacy Fay stfay New Media Guru nomichell
Staci Maynard stmaynard Social Media Trailblazer debertie
Branden Lovie brlovie Digital prophet shcarroll
Maren Jordon majordon Personalized care assistant jetim
Jone Kenna jokenna Oyster Floater alcory
Enoch Darrin endarrin Accounting Ninja diaudrey
Vita Mandy vimandy Director of First Impressions luferdinand
Arielle Kristen arkristen Light Bender jesun
Charleen Lady chlady Chief Amazement Officer jetim
Myra Tom mytom Creator of Happiness tacathie
Carlotta Beverley cabeverley New Media Guru rukay
Beth Sherrill besherrill Grand Master of Underlings laarmand
Elina Valencia elvalencia Pneumatic device and machine optimizer lathao
Jenise Broderick jebroderick Marketing Rock star wamitch
Kenia Roland keroland Twisted Brother dojamal
Mack Zack mazack VP of Misc. Stuff rukay
Sheridan Margaret shmargaret Change Magician suhobert
Ozella Rich ozrich Master of Disaster tacathie
Tomas Marin tomarin Personalized care assistant luferdinand
@odewahn
Copy link

odewahn commented Jan 25, 2024

Thanks for this great description - it was exactly the type of clear explanation I was looking for!

@jbrown123
Copy link
Author

I'm glad you found it useful

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment