I think the hardest things to debug in sps are those where it doesn't error out but the answer is wrong. Far too many programmers don't really understand their data well enough to tell that the the query doesn't return the right results. There is no substitute for understanding what the right results should be. If you don't really know, talk to a functional expert; it is not good to spend time producing a large report and then when it's published, the first time it is run for real, the users come back and tell you it obviously is wrong. It takes a lot of work to functionally understand what the data means but it will pay off in spades. There is a reason why the data analyst who is deeply involved in the guts of the database for several years can find what is wrong with a query much faster than the developer who hasn't taken the time to really understand the data. When I first came to work here, I spent a long time on a report that kept getting sent back to me by our functional expert because he would look at it for ten seconds and see something that didn't make sense to him. I learned alot from that and I don't make those kinds of errors know because I understand many more of the underlying assumptions about what the data means. When functional experts have criticisms like this (and they will, let's face it they rarely tell you everything about the requirements), then file that information away for the future and start building a personal knowldgebase about the data and what it means and what it is used for. The better you understand your database structure and the better you understand what people actually need the information for, the more effectively you can query the database.
Another sneaky thing is the error message that doesn't make sense. It tells you the insert failed on a foreign key contraint but you aren't doing an insert at all, you are doing an update. The first thing to suspect in a case like this is a trigger. To avoid these things happening to you, don't write code that inserts, deletes or updates a table without first familiarizing yourself with the triggers on dthe hood. Triggers are the culprit especially when the person who wrote them didn't consider multi-row changes to the data.
In the case you cited, where a proc runs from the query window but not from the application, alawys look first at how the application is calling the proc. As you saw, sometimes it isn't sending what you think it is sending. Profiler is a great way to capture what is really being sent.