You can use the easy but slow way and simply use either the INSERT OR UPDATE
or the UPDATE OR INSERT
(the difference being whether the update or insert is tried first) option in the txxxSqlOutput component. This is supported by most of the RDBMS components including the SQL Server one:

If you are expecting more updates than inserts then the Update or insert
option would be better performing and vice versa.
Alternatively, you can query the database beforehand and then inner join that on the primary key with your data flow to be added to the database. The matches are obviously updates and the rejects (enable Catch inner join reject
on another data flow in the tMap) are then obviously inserts.

With the tMap being configured like so:

The second way can be much more performant, especially when upserting large data sets as the first option has to attempt to insert each line, line by line, and then if it fails it then rewrites it as an update statement.
One other benefit of the second is that it can also be contained in a single batch/transaction as you are no longer having to deliberately catch a failed insert/update and then update/insert instead. This means you can make your job a lot more robust and handle errors more appropriately.