This is the wrong way to pass a complex command:
PSQL="psql -p $PGPORT -h $DBHOST -d $DB -tAc "
Instead, use arrays:
single_quote="'"
escaped_single_quote="\\'"
quoted_fname=${1//$single_quote/$escaped_single_quote}
quoted_lname=${2//$single_quote/$escaped_single_quote}
psql=( psql -p "$PGPORT" -h "$DBHOST" -d "$DB" -tAc )
dup_id=( "${psql[@]}" "SELECT id FROM ... WHERE ... '${quoted_lname}'" )
...and then using "${dup_id[@]}"
to run your command will protect you from shell injection bugs. It isn't guaranteed to protect you from SQL injection attacks (there are too many ways to perform those, and databases have too many idiosyncrasies around character set conversion, to trust the simple character-replacement-based escaping used here against hostile data), but, well, that's why folks who are concerned about correctness or security use languages that support bind parameters -- a set of which bash is not a member -- for generating SQL queries.
See also BashFAQ #50, and the BashWeaknesses page from the freenode.org #bash channel's wiki -- the latter of which explicitly calls out SQL generation as a task for which bash is unfit.