As per leffeboy’s comments, also get rid of any multiple function calls doing the same thing and replace with constants or variables i.e:
CONVERT(DATETIME, ‘2012-01-01 00:00:00’, 102) AND CONVERT(DATETIME, ‘2012-12-31 00:00:00’, 102))
to
DECLARE @Start DATETIME = CONVERT(DATETIME, ‘2012-01-01 00:00:00’, 102)
DECLARE @End DATETIME = CONVERT(DATETIME, ‘2012-12-31 00:00:00’, 102)
….. cog_invoicedate BETWEEN @Start and @End
You could break the query into smaller chunks and insert into table variables or CTE’s, also analyse the query execution plan for poor performing steps (doing it against your large query wold be a pita) and this will give you some hints on missing indexes.
Importantly, (again stealing leffeboys thunder a little) run the SQL profiler and/or index tuning wizard to identify columns should be indexed (you should probably do at least those you join on and in a WHERE clause); this will give you the biggest benefit as it will do the work for you and in 99% of cases will give you a marked improvement.
Last but not least you could hire someone to re-write it for you and improve performance (email in profile, payment in cash, bike bits, or biscuits)!