Hi SO, I am currently working on a particularly complex use-case. Simplifying below :)
First, a client record has a many-to-one relationship with a collection of services, that is, a single client may have multiple services associated with it.
Within my trigger, I am writing a Query that returns a client's id based on certain criteria. The criteria are as follows,
- If at least one service is of type B, and no services of type A exist, return id
- If at least one service is of type C, and no services of type B or A exist, return id
- If at least one service is of type D, and no services of type C or B or A exist, return id
and my current approach is to form a query similar to the one below
SELECT c.ClientId
FROM
Clients AS c
-- actually INNER JOIN is superfluous in this sample, but required for
-- other auxilliary criteria i have left out. illustrates relationship
-- between Clients and Services table
INNER JOIN Services AS s ON c.ClientId = s.ClientId
WHERE
-- has at least one service of type B, no A
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A'))) OR
-- has at least one service of type C, no B, no A
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'C')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A'))) OR
-- has at least one service of type D, no C, no B, no A
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'D')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'C')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) AND
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A')))
where [dbo].[Get_ServicesByClientIdAndType]
is a function that returns associated services for specified client id and service type. Similar to
-- this query is actually significantly more complex than shown
-- below, but this illustrates use of parameters client id and
-- service type
SELECT s.ServiceType
FROM
Services AS s
WHERE
s.ClientId = @clientId AND
s.ServiceType = @serviceType
Assuming this is optimal means of expressing this use-case, would function [dbo].[Get_ServicesByClientIdAndType]
sub-query be cached or does changing service parameter necessitate a new evaluation each invocation? [i am invoking this thing like 9 times!!! running Sql Server 2005]
I know Sql Server 2005 supports some sub-query optimizations, like caching results, but I don't know for certain under what circumstances or how to form my sub-queries [or function] such that I make the most of Sql Server's capabilities.
EDIT: reviewed my criteria above, and couldn't let go of a nagging feeling something was off. I played around with some logic in my head, and came up with this [much simpler] formulation
SELECT c.ClientId
FROM
Clients AS c
INNER JOIN Services AS s ON c.ClientId = s.ClientId
WHERE
NOT EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'A')) AND
(EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'B')) OR
EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'C')) OR
EXISTS (SELECT * FROM Get_ServicesByClientIdAndType (c.ClientId, 'D')))
essentially, there exists no scenario involving B that would lead to rejection, similarly for C and D, so any configuration is acceptable. we only care that A is not present in any selection. Arg! Charlie Brown!
leaving both expressions up for review, and I still very much appreciate the responses regarding Sql Server's performance wrt user defined functions.