There is yet one more way to accomplish the task that is very useful if both variables have been assigned within the same parenthesized block that is expanding them. The solution is similar to jeb's delayed expansion answer, except it uses a FOR variable instead of normal expansion.
@echo off
setlocal enableDelayedExpansion
:: Define a linefeed value - only needed for last variant
set LF=^
:: The two blank lines above are critical to the definition of LF
(
set A=123
set B123=some_text_in_it
rem ECHO !B%A%! will fail because A was assigned within the same block
rem This works as long as A does not contain * or ?
for %%A in ("!A!") do echo !B%%~A!
rem This works as long as A does not start with EOL character (; by default)
for /f "delims=" %%A in ("!A!") do echo !B%%A!
rem This will never fail because it disables EOL by setting it to a linefeed
for /f eol^=^%LF%%LF%^ delims^= %%A in ("!A!") do echo !B%%A!
)
The CALL trick could also be used, but comparatively it is very slow, and it is unreliable - see CALL me, or better avoid call.
The definition and use of a linefeed variable is discussed at Explain how dos-batch newline variable hack works.
Setting EOL to a linefeed is described in detail at HOW TO: FOR /F Disabling EOL or using a quote as delim. Using an LF variable instead of embedding linefeeds within the FOR statement is just an extension of the technique. It makes the code more readable.
EDIT
A simpler way to safely use the FOR technique for any valid value is to set EOL to an equal sign, since no user defined variable can contain an = in the name.
for /f "eol== delims=" %%A in ("!A!") do echo !B%%A!