RewriteCond %{HTTP_HOST} example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^blog/(.*)$ blog.php?id=$1 [NC,QSA]
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]
You seem to have mashed two different rules (HTTP to HTTPS and your blog rewrite) together and broken both. The "redirect to HTTPS" cannot work "fine", since it is processed unconditionally and would create a redirect loop (unless HTTPS requests are not processing this .htaccess file?!).
RewriteCond (conditions) are only applied to the first RewriteRule directive that follows. Together, the RewriteRule directive and preceding conditions form a single rule.
Otherwise, your regex is "OK" (except that it is arguably matching too much).
You need to reorder your directives like this:
Options -MultiViews
RewriteEngine On
RewriteCond %{HTTP_HOST} (^|\.)example\.com [NC]
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.example.com/$1 [R,L]
RewriteRule ^blog/(.*)$ blog.php?id=$1 [L,QSA]
Unless you are serving multiple domains then you can remove the initial condition that checks the HTTP_HOST.
MultiViews needs to also be disabled (it may already be), otherwise the blog to blog.php will be missing the id URL parameter.
I've removed the NC flag on the blog rewrite. Ideally, the regex should be more restrictive and only match valid id values, rather than everything. Certain special characters will result in an error with this rule.
Once this is fully tested, the HTTP to HTTPS redirect should be a 301 (permanent) redirect, not a 302 (temporary) redirect as you have currently.