首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SQL Server,将一个对象ID与映射表中的其他对象ID匹配

SQL Server,将一个对象ID与映射表中的其他对象ID匹配
EN

Stack Overflow用户
提问于 2012-04-11 01:58:05
回答 4查看 262关注 0票数 1

我完全被我用T-SQL编写的查询难住了。我有一个映射表,其中图书is存储在BookId列中,而AttributeId存储在另一列中。

代码语言:javascript
复制
CREATE TABLE BookMap (
BookId int not null,
AttributeId int not null
)

每本书可以有1到10个属性。如果图书1具有属性3-6,我希望找到也具有属性3-6的图书。由于某些原因,我想不出该如何编写这个查询。

有什么建议吗?

以下是编辑:为了进一步解释,我有以下数据:

代码语言:javascript
复制
INSERT INTO BookMap (BookId, AttributeId) VALUES (1, 3);
INSERT INTO BookMap (BookId, AttributeId) VALUES (1, 6);
INSERT INTO BookMap (BookId, AttributeId) VALUES (2, 3);
INSERT INTO BookMap (BookId, AttributeId) VALUES (2, 4);
INSERT INTO BookMap (BookId, AttributeId) VALUES (2, 6);
INSERT INTO BookMap (BookId, AttributeId) VALUES (5, 3);
INSERT INTO BookMap (BookId, AttributeId) VALUES (5, 6);
INSERT INTO BookMap (BookId, AttributeId) VALUES (6, 3);
INSERT INTO BookMap (BookId, AttributeId) VALUES (6, 5);

我想根据BookId =1进行查询,并返回恰好是3和6,但不是更多或更少的BookId。另一种方法是返回BookId列表和匹配百分比,按百分比降序排序。都不适合我的任务。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-04-11 06:43:53

编辑:下面的是几个可以产生所需结果的查询。根据索引、统计信息等的不同,它们可能具有相当不同的性能。用真实数据检查执行计划应该是有启发性的。

代码语言:javascript
复制
-- 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 )

至少在一个有点乏味的营销演示中,我很好地利用了我的时间。

票数 0
EN

Stack Overflow用户

发布于 2012-04-11 02:07:09

代码语言:javascript
复制
SELECT b.bookID
FROM BookMaP A
INNER JOIN BookMap B
   ON a.attributeID = B.AttributeID
WHERE a.BookID = 1 -- The id you want to compare against
GROUP BY b.bookID
HAVING COUNT(DISTINCT b.AttributeID) = COUNT(DISTINCT a.AttributeID)

我认为聚合和self JOIN是最好的选择。这可能需要调整,您可能只需要在HAVING子句中指定计数。

票数 1
EN

Stack Overflow用户

发布于 2012-04-11 04:43:34

我在这里测试了我的答案:http://www.sqlfiddle.com/#!3/a9eec/4 (以及我的本地服务器)

代码语言:javascript
复制
;WITH AttributeSet AS
(
  SELECT DISTINCT
    B.BookId
    , SUBSTRING((SELECT 
                    (',' + CAST(A.AttributeId AS VARCHAR(4)))
                FROM BookMap A
                WHERE A.BookId = B.BookId
                ORDER BY A.AttributeId
                FOR XML PATH ('')),2,9999) AS AttributeSet
  FROM BookMap B
)
SELECT
    MatchingBooks.BookId
FROM AttributeSet BaseBook
INNER JOIN AttributeSet MatchingBooks
    ON MatchingBooks.AttributeSet = BaseBook.AttributeSet
WHERE BaseBook.BookId = 1
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10093930

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档