First of all, I have no actual experience doing this, so I'm being theoretical here. I would not, under any circumstances, repeat your people table anywhere for any reason. I would keep another client limitation rules table that would be used to filter the results of their queries.
So they can send queries for whatever they want, even data they haven't paid for, but before the results are returned, their query results pass through another process that limits their columns and/or rows by what they've paid for.
OK, given your row limitations on aggregate functions, I see you'd need a 2 (or more) step process. First, limit by row criteria, then execute their sql, then limit by columns. Limiting by rows is the tricky part, if you need them to limit by anything that might get created in the future without schema changes. The easiest thing to do is limit (ha,ha) the row criteria they can limit by, then have one table with a bunch of columns named things like 'isLimitedByAge', 'isLimitedByRace.'
Depending on your timeline, you might need to implement this in pieces, with a less sophisticated solution now, and a more dynamic one later, after you've learned more about what most clients are querying by and therefore, likely to be willing to pay for.
For a more specific example, let's say a client sends a query, 'select * from people'. the first part would be to query clientLimitRows to see what they've paid for, like people in a certain city, or people in a certain age range. That process builds the WHERE clause for the second process that actually queries the people table, performing aggregation. Then a third process checks clientLimitColumns to remove from their results any columns they haven't paid for.
Again, just my opinion, but I think you're going to have to break your client rules down. If I had to model WHERE Company A can only access White people, born between 70 and 80, with blonde hair and between 1 and 2 cars in the family, "or", black people etc.. etc.. "or" mixed race that bla bla.. "or" ) I'd have a tables with rules (one per rule), conditions (one per OR set), and clauses (one per field/operator/value tuple connected by ANDs).
So for this rule, where you're limiting by race, age, haircolor, and numCars, OR race and blah2 OR mixedRace and blah3 or blah4 you'd have 4 rows of conditions with one or more clauses.
for
rule = 1
condition = 1
clause1 = 'race = white'
clause2 = 'age >= 70'
clause3 = 'age <= 80'
clause4 = 'haircolor = blonde'
clause5 = 'numCars >= 1'
clause6 = 'numCars <= 2'
condition = 2
clause1 = 'race = black'
clause2 = 'field2 = blah2'
condition = 3
clause1 = 'race = mixedrace'
clause2 = 'field3 = blah3'
condition = 4
clause1 = 'field4 = blah4'
the clause table has fields customerID, ruleID, conditionID, clauseID, field, operator, value
OK, I'm not sure I 100% understand what you're doing with option3, but it sounds like you're extending your people table with client markers, or introducing a rowID/clientID table with a 1-many relationship with people? Then you'd apply their paid for rules in an overnight process so the rows they can access are marked and can be limited with a join? I think it would work, but wouldn't they only get results from yesterday's queries today? If they pay for new data today, it won't be marked paid until tomorrow. I'm not sure you're missing anything, really, but if someone else has a better response, more power to them.
OK, I think I see where you're going. You want to create a table overnight that extends the people table with a clientID field, so each clientID has their own set of queryable rows? And you can't do that on the fly? When they send a query, first create their set of rows, then apply their query to that set?