You shouldn't try to select a new custom ID like this before you actually insert the record, as someone else may insert that same value before you. So here's how you can potentially run your table inserts:
insert into John_IEP_Crossing_Dock_Shipment (MyCol1, MyCol2, ID)
select @MyFormValue1,
@MyFormValue2,
convert(varchar(10), current_timestamp, 20)
+ '-'
+ right('000' + cast(cast(right(coalesce(max(ID), '0'), 4) as smallint) + 1 as varchar(4)), 4)
from John_IEP_Crossing_Dock_Shipment
where ID like convert(varchar(10), current_timestamp, 20) + '%'; -- like may use an index in this case
We're coming up with the ID during the insert, not before. This should mostly solve the contention issue (heck, you can only have 9,999 inserts per day anyway with that 4-digit ID suffix) and coalesce will take care of the case where you have no data yet today (and insert ID "...-0001").
If you need to select this record immediately after the insert to display to the user, you could use the output keyword.
If it does not already have one, adding a unique constraint of some sort to this ID column is mandatory. At least then you could handle the exception and allow the user to try the insert again if contention is still an issue (I'm not expert enough to say that these inserts could never collide or if you should lock the table to prevent such a thing).
I agree with @MartinSmith and I would rather use a create date column with an identity column (or maybe 2012's sequence), and thus be able to calculate this ID column. I also understand that some part numbering schemes should just be stored, and sometimes skipped numbers aren't valid (unless there are deletes).
I welcome feedback from those that know more.
sql-server.WHEREclause is dependent on the date, so it's very possible there is no data with today's date but there was with yesterdays.IDENTITYscheme soIDis like2013-06-140-0001? I wouldn't bother anyway as this is difficult to get right under conditions of concurrency but looks like you will get this problem every day unless you change the query to handle the first one of the day. (whenMAX(ID)isNULL)SELECTand getting given the same "next" identity value? I would just have a separate column forcreate_dateand have a normalIDENTITYcolumn.