With standard sh syntax:
case ${table_name##*_} in
("$table_name" | "" | *[!0-9]*) echo >&2 incorrect;;
(*) echo correct;;
esac
That is check that $table_name stripped of everything up to the right-most _ in it is neither $table_name itself (which would mean $table_name had no _), nor the empty string, nor contained a non-digit character.
The standard command to match a string against a regexp is expr though it has a few issues and doesn't make for very legible code:
if expr " $table_name" : '.*_[0-9]\{1,\}$' > /dev/null; then
echo Correct
else
echo >&2 Incorrect
fi
The leading space is to avoid issues for values of $table_name like + or --help. regexps are anchored at the beginning implicitly (hence the .*) but not end (hence the $) and the result (0 or 1 here) is output on stdout in addition to being reflected in the exit status, hence the redirection to /dev/null.
Some [ implementations like the [ builtin of zsh and yash have a =~ operator for that (using ERE, though you can change that to PCRE with zsh):
if [ "$table_name" '=~' '_[0-9]+$' ]; then
echo Correct
else
echo >&2 Incorrect
fi
bash, zsh and ksh93 have a =~ operator inside their [[...]] construct, though the syntax and the behaviour wrt quoting varies between implementations. Best is to use variables as already shown by @BLayer
zsh -o extendedglob and ksh (or bash -O extglob or zsh -o kshglob that support a subset of ksh globs) have glob operators that are functionally equivalent to regexps albeit with a different syntax.
Translation RE -> ksh-glob / zsh-glob:
[0-9] -> [0-9] / [0-9]
x+ -> +(x) / x##
$ or ^ -> implicit / implicit
. -> ?
.* -> * (or *(?)) / * (or ?#)
So in ksh (or bash -O extglob or zsh -o kshglob):
case $table_name in
(*_+([0-9]) echo correct;;
(*) echo >&2 incorrect;;
esac
In zsh -o extendedglob:
case $table_name in
(*_[0-9]##) echo correct;;
(*) echo >&2 incorrect;;
esac
zsh also has the <x-y> extended glob operator to match decimal numbers from x to y so you can also write it (*_<->) echo correct.
In those shells, those globs can also be used on the right hand side of the = aka == [[...]] operator.