How to stop get_queried_object_id() returning child term id’s also

The issue I have is that if I use get_queried_object_id, the archive
page for the parent term shows the shortcode for the parent term and
the first child term.

That’s not what’s happening. get_queried_object_id() will only return the ID of the current category. When you add [0] you’re just breaking the condition check meaning that only in_category() is being checked. The problem is how you’re using in_category().

in_category() is supposed to be used inside the loop, and is checking the current post. When used on an archive page this is going to check the first post on the page. The reason your shortcode is being output twice is because the get_queried_object_id() check is true for the parent category, and the in_category() check for the child category is (apparently) true for the first post.

If you want to check which archive is being displayed get rid of in_category() entirely, and make sure to check is_category() to ensure that the queried object is a category.

if ( is_category() && $emk_current_term_id === 141293 ) {
    echo do_shortcode( '[emk_shortcode_02]' );
}

if ( is_category() && $emk_current_term_id === 305 ) {
    echo do_shortcode( '[emk_shortcode_02]' );
}

Just note that checking is_category() is redundant if this code is in category.php.