Another option which just occurred to me is to do something known as a Cross-Database JOIN. What this basically means is that you would build up your overall database from several smaller databases; in an extreme case, you could do it to where each database contains only a single table. From there, since you can assign permissions on each database through careful use of user accounts, you can effectively get table level permissions.
Since that was likely pretty confusing, let me try to illustrate with an example:
Say you have three tables: One for client info (ci), one for posts a client has made (cp), and one for notes an administrator has made about particular users (an). The client is entitled to view any client’s info and any user posts, but no client may ever view any administrator notes – those are for admin only.
We can organize the database as follows:
client_db contains ci and cp
admin_db contains an
Further, we will need database users:
client_db_user with read/write on client_db
admin_db_user with read/write on client_db and admin_db
Now, if a client wants to see all of his posts, he uses the client_db_user account and issues a 'SELECT * FROM client_db.cp posts WHERE posts.client_id = ?'
If a client wants to see all of the admin notes logged against him, he can try to ‘SELECT * FROM admin_db.an notes WHERE notes.client_id = ?’ but he’ll get a permission denied error because client_db_user cannot read from admin_db.
However, if an admin wants to have all of a user’s informaiton, and a list of the admin notes logged against a user, the admin can use the admin_db_user to ‘SELECT * FROM client_db.ci info JOIN admin_db.an notes ON notes.client_id = info.client_id WHERE info.client_id = ?’
As a disclaimer, please keep in mind that I’ve never used this technique in practice, and pretty much just dreamed it up on the spot. I think it will work (I did check to see that Dreamhost allows cross-database joins), but I’ll make no guarantees about efficiency or maintainability. Indeed, for what you’ve described in your post, this is likely overkill. I also don’t guarantee that the code aboveis spot-on accurate, though I think it would work.