I do my best not to dynamically construct SQL queries. I have come aboard projects several times that do this, and it has always been a source of trouble. Compared to stored procedures, dynamically constructed SQL will incur query parsing and planning costs much more often, will incur higher data transmission costs always, and are much more likely to result in unforeseen, unwieldy, unperformant, and otherwise problematic queries. Basically, this approach is guaranteed not to scale.
Instead, if at all possible, maintain a set of tuned stored procedures that collectively cover your query space. In some cases, the applicable stored procedure will be more general than you require (e.g. have a "WHERE [Foo] = @foo OR @foo IS NULL" clause that you could have left off entirely if you knew that the query was never going to match on Foo). Either accept that cost or write a specialized stored procedure for situations when the more general stored procedure becomes a bottleneck.
If you ignore my advice and do construct SQL dynamically, then at very least use parameters instead of values wherever you can. If you construct "WHERE [Foo] = 1" for one query and "WHERE [Foo] = 2" for another, both queries will be compiled separately. If instead you construct "WHERE [Foo] = @foo" for both and pass @foo = 1 for the first and @foo = 2 for the second, then you will at least just incur the compile cost once and the cached query plan will be used for the second call.