编辑:以下是产生所需结果的几个查询。根据索引,统计信息,它们可能具有相当不同的性能......。用真实数据检查执行计划应该是有启发性的。
-- Sample data.
declare @BookMap as Table ( BookId int not null, AttributeId int not null )
insert into @BookMap ( BookId, AttributeId ) values
(1, 3), (1, 6),
(2, 3), (2, 4), (2, 6),
(5, 3), (5, 6),
(6, 3), (6, 5)
select * from @BookMap
-- Target book.
declare @BookId as Int = 1
select AttributeId
from @BookMap
where BookId = @BookId
-- Books with matching attributes using NOT EXISTS in the last line.
select BookId
from (
select BookId, Sum( 1 ) as MatchCount
from @BookMap as BM
where BookId <> @BookId and AttributeId in ( select AttributeId from @BookMap where BookId = @BookId )
group by BookId ) as Ellen
where
-- The number of matching attributes is the number of desired attributes.
MatchCount = ( select Count( 42 ) from @BookMap where BookId = @BookId ) and
-- There are no other attributes as determined by looking for additional attributes.
not exists ( select 42 from @BookMap where BookId = Ellen.BookId and AttributeId not in ( select AttributeId from @BookMap where BookId = @BookId ) )
-- Books with matching attributes using COUNT() in the last line.
select BookId
from (
select BookId, Sum( 1 ) as MatchCount
from @BookMap as BM
where BookId <> @BookId and AttributeId in ( select AttributeId from @BookMap where BookId = @BookId )
group by BookId ) as Ellen
where
-- The number of matching attributes is the number of desired attributes.
MatchCount = ( select Count( 42 ) from @BookMap where BookId = @BookId ) and
-- There are no other attributes as determined by counting attributes.
( select Count( 42 ) from @BookMap where BookId = Ellen.BookId ) = ( select Count( 42 ) from @BookMap where BookId = @BookId )
-- Display the attributes that we must, and must not, match.
select distinct AttributeId,
case when AttributeId in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustMatch,
case when AttributeId not in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustNotMatch
from @BookMap
-- Get the similar books using SUM() in the last line.
; with A as (
-- All attributes with MustMatch/MustNotMatch flags.
select distinct AttributeId,
case when AttributeId in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustMatch,
case when AttributeId not in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustNotMatch
from @BookMap
)
select BookId
from @BookMap as B inner join
A as A on A.AttributeId = B.AttributeId
where BookId <> @BookId
group by BookId
having Sum( MustNotMatch ) = 0 and Sum( MustMatch ) = ( select Count( 42 ) from @BookMap where BookId = @BookId )
-- Get the similar books using MAX() in the last line.
; with A as (
-- All attributes with MustMatch/MustNotMatch flags.
select distinct AttributeId,
case when AttributeId in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustMatch,
case when AttributeId not in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustNotMatch
from @BookMap
)
select BookId
from @BookMap as B inner join
A as A on A.AttributeId = B.AttributeId
where BookId <> @BookId
group by BookId
having Max( MustNotMatch ) = 0 and Sum( MustMatch ) = ( select Count( 42 ) from @BookMap where BookId = @BookId )
-- Get the similar books without using SUM() and with extra credit for using a Cartesian product.
-- Using MAX() in the last line.
; with A as (
-- All attributes with MustMatch/MustNotMatch flags.
select distinct AttributeId,
case when AttributeId in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustMatch
from @BookMap
),
B as (
-- All books except the search pattern book.
select distinct BookId
from @BookMap
where BookId <> @BookId ),
P as (
-- Cross product plus original data and coefficient of wickedness.
select B.BookId, A.AttributeId, A.MustMatch,
case
when MustMatch = 1 and T.AttributeId is not NULL then 0
when MustMatch = 0 and T.AttributeId is NULL then 0
else 1
end as Wicked
from B cross join
A left outer join
@BookMap as T on T.BookId = B.BookId and T.AttributeId = A.AttributeId
)
select BookId
from B
where ( select Max( Wicked ) from P where P.BookId = B.BookId ) = 0
-- Get the similar books without using SUM() and with extra credit for using a Cartesian product.
-- Using NOT EXISTS in the last line.
; with A as (
-- All attributes with MustMatch/MustNotMatch flags.
select distinct AttributeId,
case when AttributeId in ( select AttributeId from @BookMap where BookId = @BookId ) then 1 else 0 end as MustMatch
from @BookMap
),
B as (
-- All books except the search pattern book.
select distinct BookId
from @BookMap
where BookId <> @BookId ),
P as (
-- Cross product plus original data and coefficient of wickedness.
select B.BookId, A.AttributeId, A.MustMatch,
case
when MustMatch = 1 and T.AttributeId is not NULL then 0
when MustMatch = 0 and T.AttributeId is NULL then 0
else 1
end as Wicked
from B cross join
A left outer join
@BookMap as T on T.BookId = B.BookId and T.AttributeId = A.AttributeId
)
select BookId
from B
where not exists ( select 42 from P where P.BookId = B.BookId and Wicked = 1 )
至少我在一个有点乏味的营销演示中充分利用了我的时间。