L'explication est, selon le manuel :
Le corps du DO
instruction est une chaîne entre guillemets en dollars. Donc pas d'interpolation à l'intérieur de la chaîne.
Puisqu'il doit s'agir d'une chaîne littérale, vous ne pouvez pas non plus concaténer des chaînes à la volée. Le manuel :
Mais vous pouvez concaténer la chaîne puis l'exécuter.
Bold emphase mienne. Il vous suffit de bien citer :
test=# \set test 'some value'
test=# \set code 'DECLARE v_test text := ' :'test' '; BEGIN RAISE NOTICE ''test var is: %'', v_test; END'
test=# DO :'code';
NOTICE: test var is: some value
DO
test=#
Mais je préfère créer une fonction (temporaire) et passer la valeur en paramètre (où l'interpolation psql fonctionne). Détails dans cette réponse connexe sur dba.SE :