Depois de alguns anos, a questão ainda é importante ...
Uma regra prática simples para mim: se for uma restrição lógica ou uma expressão onipresente (instrução única), coloque-a no banco de dados (sim, chaves estrangeiras e restrições de verificação também são lógicas de negócios!). Se for processual, contendo loops e ramificações condicionais (e realmente não pode ser transformado em uma expressão), coloque-o no código.
Evitar DBs de despejo de lixo
Tentativas de colocar realmente toda a lógica de negócios no código do aplicativo provavelmente degenerarão o banco de dados (relacional) em um lixeira, onde o design relacional é quase totalmente omitido, onde os dados podem ter qualquer estado inconsistente e a normalização está ausente (geralmente XML, JSON , CSV etc. colunas da lixeira).
Esse tipo de lógica somente de aplicativo é provavelmente uma das principais razões para o surgimento do NoSQL - é claro, com a desvantagem de que o aplicativo precisa cuidar de toda a lógica em si, o que foi incorporado ao DB relacional por décadas. No entanto, os bancos de dados NoSQL são mais adequados para esse tipo de manipulação de dados, por exemplo, documentos de dados mantêm uma "integridade relacional" implícita dentro de si. Para bancos de dados relacionais, é simplesmente abuso, causando ainda mais problemas.
Expressões (baseadas em conjunto) em vez de código processual
Na melhor das hipóteses, toda consulta ou operação de dados deve ser codificada como uma expressão, em vez de código processual. Um ótimo suporte para isso é quando as linguagens de programação suportam expressões, como LINQ no mundo .NET (infelizmente, apenas consultas atualmente, sem manipulação). No lado do banco de dados relacional, foi ensinado por um longo tempo a preferir expressões de instrução SQL em vez de loops de cursor procedurais. Portanto, o banco de dados pode otimizar, executar a operação em paralelo ou o que for útil.
Utilize mecanismos de integridade de dados de banco de dados
Quando se trata de RDBMS com restrições de Chave estrangeira e verificação, colunas calculadas, possivelmente gatilhos e visualizações, este é o local para armazenar a lógica comercial básica no banco de dados. A normalização adequada ajuda a manter a integridade dos dados, para garantir uma instância única e distinta dos dados. Mesmo se você precisar duplicá-lo no código e no banco de dados, esses mecanismos básicos de integridade dos dados não devem ser omitidos!
Procedimentos armazenados?
Atualmente, os procedimentos armazenados raramente são necessários, pois os bancos de dados mantêm planos de execução compilados para SQL e os reutilizam quando a mesma consulta volta, apenas com parâmetros diferentes. Portanto, o argumento de pré-compilação para SPs não é mais válido. Pode-se armazenar ou gerar automaticamente consultas SQL no aplicativo ou ORM, que encontrará planos de consulta pré-compilados na maioria das vezes. SQL é uma linguagem de expressão, desde que você não use explicitamente elementos procedimentais. Portanto, na melhor das hipóteses, você usa expressões de código que podem ser traduzidas para SQL.
Enquanto o lado do aplicativo, incluindo o ORM gerado, SQL, não está mais dentro do banco de dados, ao contrário dos Procedimentos Armazenados, continuo contando-o como código do banco de dados. Como ainda requer conhecimento de SQL e banco de dados (exceto o CRUD mais simples) e, se aplicado corretamente, funciona muito diferente do código de procedimento geralmente criado com linguagens de programação como C # ou Java.