+1  A: 

How about something like this:

  SELECT DISTINCT sign_pk
    FROM table_a
   WHERE sign_pk NOT IN
    (   
      SELECT DISTINCT front_sign sign
        FROM table_c
       UNION
      SELECT DISTINCT rear_sign sign
       FROM  table_c
    )
dcp
Querying each sign_pk against all of the front_sign and back_sign values is a little impractical, since all the tables have millions of rows, and the front_sign and back_sign columns aren't indexed. That seems like it would lead to two table scans of table c.
Lazy Bob
LazyBob, it's going to be difficult to design an efficient solution given the bad design of the hypothetical tables. If you draw the tables you'll see that the relationships form a triangle. The "signs at locations" table should only have 1 sign_pk in it and have a "sign type" column.
AdamH
dcp, I think yours is probably the best possible solution given the table structure. I wouldn't bother with the "distinct" *within* the IN clause, it forces unnecessary work onto sybase for no actual improvement.
AdamH
A: 

ANSI outer join is your friend here. *= has dodgy semantics and should be avoided

select distinct a.sign_pk, a.company_pk
from a join b on a.company_pk = b.company_pk 
left outer join c on b.company_location = c.company_location 
                  and (a.sign_pk = c.front_sign or a.sign_pk = c.back_sign) 
where c.company_location is null

Note that the where clause is a filter on the rows returned by the join, so it says "do the joins, but give me only the rows that didn't to join to c"

Outer join is almost always faster than NOT EXISTS and NOT IN

Terence