I redesigned the underlying code of my Books page, making it cleaner and more easily maintainable. As an unforeseen by-product of this, the two bugs which have been bugging me for some time (the Multiple Role Bug and the String Length Restriction Bug, as I call them) magically vanished! Also, browsing by category or author (or more generally, by any method which requires many-to-many tables to be joined) used to mean that under each book, only the category/author under consideration would show (even though a book might be written by many authors or be in many categories); no more! And there's a new feature: For all non-book views on the main page, you get the number of books in a category in parenthesis.
The Multiple Role Bug meant that for books where some authors had roles (editor, illustrator, translator, etc.), I'd get two sets of roles. (Example: The Solaris Book of New Science Fiction.) I had this fixed with a kludge, deleting every other role. However, this worked most places, but not all. It turned out that I'd get n sets of roles, where n is the number of categories in which a book is (most books are in two categories).
The String Length Restriction Bug would cut off the comma-separated strings containing the authors' names and ids long before its actual limit was reached, so that anthology books with lots of contributing authors were bungled. (Example: Dangerous Visions.) I never could figure out how to fix it.
However, I looked at my database queries, and designed them a little more logically. Before, I had one master query per view (by category, by series, single books, special criteria, etc.) and sent along
GROUP_CONCAT()s for author names, ids, and roles, and for category names and ids, and then had my home-grown
print_book() function work on the strings. Now, I do two separate queries inside the function to fish out author and category information, so that instead of one massive and unwieldy master query, I have three smaller ones. The lesson? Don't be afraid to use several queries.
I'm so happy with the way it works now that in a spirit of why-not-ism I added all the rest of my books to the database. So in the future when I've read a book, making it appear in the various views is as easy as flipping a boolean value. This should serve as an incentive to read more books (something I've really been neglecting lately).