A very difficult problem. It seems users will be added at high speed, with coupons at a fairly regular frequency.
Adding SQL to a table that will be used dynamically is workable - at least you get a new execution plan - BUT your plan cache may pop up.
I have the feeling that launching one coupon for all users will probably be your most effective query, because one set of criteria, which will be quite selective for users at the beginning and the total number of coupons, will be small, while all coupons for one user are Separate criteria for each coupon for this user. Running all coupons for all users may still work well, even if it efficiently cross-connects first - I assume it will just be dependent.
In any case, the case for all coupons for all users (or cut anyway, in fact) will be something like this:
SELECT user.id, coupon.id FROM user INNER JOIN coupon ON ( CASE WHEN <coupon.criteria> THEN <coupon.id>
To generate coupon rules, you can relatively easily concatenate strings with one hit (and you can combine the design of individual rule lines for a coupon with AND with an additional internal template):
DECLARE @outer_template AS varchar(max) = 'SELECT user.id, coupon.id FROM user INNER JOIN coupon ON ( {template} ELSE NULL ) = coupon.id '; DECLARE @template AS varchar(max) = 'CASE WHEN {coupon.rule} THEN {coupon.id}{crlf}'; DECLARE @coupon AS TABLE (id INT, [rule] varchar(max)); INSERT INTO @coupon VALUES (1, 'user.Age BETWEEN 20 AND 29') ,(2, 'user.Color = ''Yellow'''); DECLARE @sql AS varchar(MAX) = REPLACE( @outer_template ,'{template}', REPLACE(( SELECT REPLACE(REPLACE( @template ,'{coupon.rule}', coupon.[rule]) , '{coupon.id}', coupon.id) FROM @coupon AS coupon FOR XML PATH('') ), '{crlf}', CHAR(13) + CHAR(10))); PRINT @sql; // EXEC (@sql);
There are ways to finish the game - play here: http://data.stackexchange.com/stackoverflow/q/115098/
I would consider adding calculated columns (possibly stored and indexed) to help. For example, a calculated column with age - unstable, most likely will work better than a scalar function.
I would consider the issue of this with a table that says whether the coupon is valid for the user and when it was last confirmed.
It looks like age may change, and the user may become valid or invalid for the coupon as birthday passes.
When a user logs in, you can create a background task to update your coupons. Subsequent logins will not need to be updated (since this is unlikely to change until the next day or the triggering event).
A few ideas.
I would also add that you should have a way to check the coupon before approving it, to make sure there are no syntax errors (since SQL is arbitrary or arbitrary) - this can be done relatively easily - perhaps a test user table (test_user as the user in the generated code template) it is required to contain pass and failure lines, and coupon rules on them. Not only EXEC should work - the rows it returns should be expected and only expected rows for this coupon.