bit return any NULL values? because NOT IN will fail if the list contains NULL.
You could test that theory by changing your code to
WHERE (UPC NOT IN
WHERE UPC IS NOT NULL
but I favour the NOT EXISTS approach, already suggested. EXISTS only has to find one matching row, whereas IN (SELECT ... will potentially make a complete list and THEN check if it matches.
I also tend to use an OUTER JOIN - but that's just down to personal preference. My reason for doing that is I can easily change it to report on this that DO exist, rather than those that DON'T - seems to come up a fair bit during debugging "Why doesn't this £$%^&* thing work?" !!
FROM dbo.Items i
LEFT OUTER JOIN dbo.SDFD s
ON s.UPC = i.UPC
WHERE s.UPC IS NULL -- Comment this out to find what DOES match