如何处理多个一对多的关系?

时间:2009-08-05 20:04:52

标签: sql database select join

我有一个包含多个表的数据库,其中5个专用于特定的发布类型。这5个中的每一个与状态表和人员表具有一对多关系。所有这些表都使用独特的“pubid”绑定在一起。我有一个视图,其中包括pubid(所有5种类型),以及它们相关的关键字。当用户进行关键字搜索并且结果跨越这5个发布类型表中的1个以上时,我真的不确定如何处理它。

如果只有一个发布类型(因此只有一个表格具有1->多个),那么使用嵌套连接很容易实现,例如:

SELECT * FROM articles 
  INNER JOIN status ON articles.spubid = status.spubid 
  INNER JOIN people ON articles.spubid = people.spubid 
  WHERE people.saffil = 'ABC' ORDER BY people.iorder, articles.spubid;

在该示例中,“文章”是我提到的具有1>许多关系的5个表格之一。让我们说关键字搜索会带来包含文章,书籍和论文的结果。如何通过许多不同的表实现同样的目标?如果我在这种情况下弄清楚如何使用JOIN,那么笛卡尔积很大,以至于我认为将其解析成可用格式的开销太高了。在这种情况下,我的其他选择是什么?

5 个答案:

答案 0 :(得分:2)

为什么他们在单独的表中?列不同吗?您希望返回哪些列(从未在生产中使用select *,特别是使用连接),它们在查询中的不同类型之间是否有所不同?

如果您可以使列相同,我建议您使用UNION ALL。即使通过在union语句的每个部分中提供所需的所有内容来使列不同(为表组没有的那些列赋予null值),您仍然可以获得所需的内容。简化代码如下:

SELECT articlename, articlestatus, author, ISBN_Number 
FROM articles 
  INNER JOIN status ON articles.spubid = status.spubid   
  INNER JOIN people ON articles.spubid = people.spubid   
WHERE people.saffil = 'ABC' 
UNION ALL 
SELECT papername, paperstatus, author, null
FROM papers 
  INNER JOIN status ON papers.spubid = status.spubid   
  INNER JOIN people ON papers.spubid = people.spubid   
WHERE people.saffil = 'ABC' 

答案 1 :(得分:2)

您可以创建一个视图,该视图是所有各种表的并集。棘手的一点是确保UNIONed的所有查询都具有相同的字段,因此您需要在每个查询中存根。这是一个只有两个表的简化示例:

CREATE VIEW AllTables AS
  SELECT Afield1, Afield2, NULL as Bfield1, NULL as Bfield2 FROM Atable
    UNION
  SELECT NULL as Afield1, NULL as Afield2, Bfield1, Bfield2 FROM Btable;

当然,如果需要,您可以使用除NULL之外的其他内容作为存根值。然后针对视图运行查询。如果您需要根据发布类型更改格式,可以将原始表包含在视图中(即添加"'magazine' AS publication_type"或类似于您的每个选择的内容)。

答案 2 :(得分:0)

也许你可以为5种类型(vwBook,vwArticle等)中的每一种创建视图。

当你正在搜索时,也许会调用一个存储过程,它将使用你抛出的关键字来使用所有5个视图。 5个结果中的每一个都可以进入存储过程中的表变量。

当然,根据您的需要修改。这是一个广泛的例子:

create proc MySearch

@MySearchTerm varchar(50)

AS
    DECLARE @SearchResultsTABLE
    (
     Type      varchar(10) -- the view you found the result in.
    ,ID        int -- the primary key of the Book record. whatever you want to link it back to the original
    ,FoundText varchar(512)
    --etc
    )

    INSERT INTO @SearchResults(Type, ID, FoundText)
      SELECT 'Articles', ID, SomeKeyField
      FROM vwArticle
      WHERE SomeKeyField LIKE '%' + @MySearchTerm + '%'

    INSERT INTO @SearchResults(Type, ID, FoundText)
      SELECT 'Book', ID, SomeKeyField
      FROM vwBook
      WHERE SomeKeyField LIKE '%' + @MySearchTerm + '%'

    --repeat as needed with the 3 other views that you'd build

    SELECT * FROM @SearchResults

答案 3 :(得分:0)

我真的不喜欢这里的桌子设计。但是我想从头开始重新设计整个数据库有点太极端了。

鉴于表设计,我认为你将不得不使用UNION并在每个表中指定列。我知道这是一个怪物,但是当你设计的表格中有很多“几乎”相似的列时会发生这种情况。

HLGEM是对的。在永久存储的查询中使用“select *”非常危险。

答案 4 :(得分:0)

我们最终创建了一个非常精细的视图,其中包含1-many表作为视图中的数组列。这允许在单个视图上执行单个查询,并返回所有必需的数据。视图定义非常复杂,但它像冠军一样工作,真正的技巧是使用PostgreSQL中的ARRAY()函数。