Normalmente, eles devem ser evitados, mas o recurso existe por um motivo e há momentos para usá-los. Eu diria que mais de 90% dos cursores que vi não são necessários. Se você os estiver usando para operações CRUD, isso quase sempre pode ser refeito de maneira baseada em conjunto. Muitas vezes vi pessoas usarem cursores para isso porque não sabem como usar junções em uma atualização ou exclusão ou que podem usar uma instrução select em vez de uma cláusula de valores em uma inserção. Outro uso desnecessário quando as pessoas pensam que precisam deles para um processamento um pouco mais complexo que na verdade poderia ser facilmente tratado com uma instrução case.
Às vezes, os cursores são mais rápidos para calcular algo como um total em execução.
Os cursores também são úteis para várias execuções de um proc armazenado configurado para manipular apenas um valor de entrada por vez. Eu não uso esse recurso para executar procs armazenados pelo usuário (a menos que eu saiba que estarei atingindo um conjunto muito pequeno de dados), mas é muito útil para administradores de banco de dados quando precisam executar procs do sistema em várias tabelas.
Se você está criando emails em SQl (não é o melhor lugar para fazer isso, mas em alguns sistemas é onde eles fazem isso) e não quer que todo o público do email veja as outras pessoas da lista ou você quer personalizar cada e-mail com informações sobre o destinatário, os cursores são o caminho a percorrer.
Cursores ou loops também podem ser usados para processar lotes de registros se toda a inserção/atualização/exclusão baseada em conjunto demorar muito e travar as tabelas. Essa é uma espécie de híbrido entre os cursores e a solução baseada em conjunto e geralmente é a melhor para grandes mudanças nos sistemas de produção.