MSSQL is not that bad really, the main problems I have found are mostly with the way people use it.
One problem is that there are some types of table alteration you can't do with ALTER TABLE - some alterations are simply impossible. In any case, the standard recommended way is to rename the table, create a new one and transfer all the data (this can of course be very slow and blocks clients, but internally that's probably all an ALTER TABLE would have done anyway).
Another issue is the difficulty of dropping object which have dependent objects with a system-generated name. Whenever you assign a column a default value in MSSQL (A common thing, you might think), it will create a constraint object with a system-generated name (Which won't be the same in different installations).
If you subsequently want to drop a column with a default value, it's necessary to drop this system-generated constraint first. This is tricky because it doesn't have a fixed name from one installation to another and they must be dropped by name.
I eventually gave up and wrote a rather complicated nasty stored procedure to work out the name of the constraint, drop it, then drop the column.
The only reasonable way of keeping schemas in synch between dev / staging, production etc, is to script all changes. MSSQL makes scripting some schema changes VERY hard.
The GUI generates scripts for you to script a given schema change, but this has one major flaw - these scripts contain the hard-coded names of dependent objects, which have system-generated names, so these scripts often won't work on another server.
Mark