It's not really the only way (PostgreSQL has recursive queries), but it's definitely the most convenient (and in many cases the most efficient) way if you're not worried about referential integrity.
https://www.postgresql.org/docs/current/static/queries-with....
consider there are 3 tables clients/projects/tasks with FKs between them.
Please paste the query that returns all the information above using "with recursive"
This is how the communication between the client an PG goes https://www.pgcon.org/2014/schedule/attachments/330_postgres...
- client sends an SQL command - server replies with RowDescription detailing the structure - after that a DataRow message is sent for every row - finally, the server sends CommandComplete and ReadyForQuery
So inherently the protocol can only represent a 2D array.