连接后SQL选择问题

时间:2015-03-23 14:51:29

标签: sql sql-server tsql join

当我想在连接两个表后选择一些行时,我遇到了一些问题。

我有3张桌子,图书馆可以包含多本书, 书籍属于一个或多个图书馆,并且书籍可用的每种语言都有BookTypeId。

Library
Id|Name

Books
Id|IsAvailable|LibraryId|BookTypeId

BookType
Id|DisplayName|Language

加入后,创建此表

Id|Name    |IsAvailable|Language

0 |library1|          0|Book1_EN
0 |library1|          1|Book1_FR 
0 |library1|          0|Book1_ES
1 |library2|          1|Book1_EN
1 |library2|          1|Book1_FR
1 |library2|          1|Book1_ES
1 |library2|          1|Book2_EN

图书馆可以包含多本书籍 书籍属于一个或多个图书馆,并且书籍可用的每种语言都有BookTypeId。

SELECT l.Id, l.Name, BookType.TypeName, Books.IsAvailable
FROM [Library] l
RIGHT JOIN Books ON l.Id = Books.LibraryId             
LEFT JOIN BookType ON Books.BookTypeId = BookType.Id     
WHERE (BookType.Language='Bookname1_FR' AND Books.IsAvailable='1') AND (BookType.Language='Bookname2_EN' AND Books.IsAvailable='1') 
ORDER BY l.Id ASC

但是我的请求返回null,我认为这是因为我的连接在我的连接表中重复了一些库表的原始。

你知道我如何修改我的WHERE子句以获得同时出售这两本书的图书馆吗?也许通过使用2 SELECT和INTERSECT结果?

4 个答案:

答案 0 :(得分:1)

SELECT l.Id, l.Name, BookType.TypeName, Books.IsAvailable
FROM [Library] l
RIGHT JOIN Books ON l.Id = Books.LibraryId             
LEFT JOIN BookType ON Books.BookTypeId = BookType.Id     
WHERE (BookType.Language='Bookname1_FR' AND Books.IsAvailable='1') AND (BookType.Language='Bookname2_EN' AND Books.IsAvailable='1') 
ORDER BY l.Id ASC

BookType.Language不能是Bookname1_FR'和' Bookname2_EN'同时。可能是你的意思:

SELECT l.Id, l.Name, BookType.TypeName, Books.IsAvailable
FROM [Library] l
RIGHT JOIN Books ON l.Id = Books.LibraryId             
LEFT JOIN BookType ON Books.BookTypeId = BookType.Id     
WHERE BookType.Language IN('Bookname1_FR', 'Bookname2_EN') AND Books.IsAvailable='1'
ORDER BY l.Id ASC

答案 1 :(得分:0)

您的WHERE条件无法满足。修改那个。也许你的意思是OR?

WHERE (BookType.Language='Bookname1_FR' AND Books.IsAvailable='1') OR (BookType.Language='Bookname2_EN' AND Books.IsAvailable='1')

更新:您应该根据您的要求使用GROUP BY

SELECT l.Id, l.Name, BookType.Language
FROM [Library] l
RIGHT JOIN Books ON l.Id = Books.LibraryId             
LEFT JOIN BookType ON Books.BookTypeId = BookType.Id         
WHERE Books.IsAvailable='1'
GROUP BY l.Name, BookType.Language
HAVING COUNT(*)>1
ORDER BY l.Id ASC

答案 2 :(得分:0)

首先你有坏的where子句。当您在连接右侧的表上放置where条件(ID不为null)时,将左连接更改为内连接。当您需要这样做时,您应该将其置于ON状态。读: http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

现在,您的WHERE条件(应该在前一段中的ON子句中)是不可能满足的,让我解释原因。

(BookType.Language ='Bookname1_FR'AND Books.IsAvailable ='1')AND(BookType.Language ='Bookname2_EN'AND Books.IsAvailable ='1')

在任何一条记录中,字段BookType.Language只有一个值。你要求它同时是'Bookname1_FR'和'Bookname2_EN'。如果您希望所有具有这两个值之一的记录都是OR条件。

如果您需要数据包含始终具有“Bookname1_FR”和“Bookname2_EN”的子记录的图书记录,则您需要为每个条件两次加入Book类型表。在这种情况下,我不确定您是否希望开始使用LEFT。如果两个记录都必须存在,则可能需要内连接。作为猜测,如果您希望这本书能够记录两种语言,那么这可能更符合您的要求:

SELECT L.Id, L.Name,  B.IsAvailable, BT1.TypeName,   BT2.TypeName
FROM [Library] L
JOIN[Books] B
  ON Ll.Id = B.LibraryId             
JOIN BookType BT1 
    ON BT1.BookTypeId = BookType.Id     
JOIN BookType BT1 
    ON BT2.BookTypeId = BookType.Id  
WHERE (BT1.Language='Bookname1_FR'  
AND BT2.Language='Bookname2_EN' 
AND B.IsAvailable='1' 
ORDER BY L.Id ASC

我也改变了右连接到内部连接,因为你正在寻找数据字段形式的Libraby表,这似乎是查询所必需的。由于它位于外连接的错误一侧(很少想要通过可能包含大量空值的字段进行排序),我怀疑你真的想要一个INNER连接。

您永远不想在同一个查询中混合使用左连接和右连接,因为当您尝试在两年后尝试更改查询时,弄清楚数据交叉点应该是什么。我注意到的另一件事是你只有一个表别名。如果你是别名,最好对所有表进行别名(我确实认为别名使它更易于阅读)。你需要考虑使这段代码更易于维护。

答案 3 :(得分:0)

这将返回两行,每行一种语言。我想这就是你想要的,因为TypeName在结果中。这不是我在你的表格模式中看到的专栏。

外部联接并不是真的有必要,所以我将它们切换到内部联接。

SELECT l.Id, l.Name, bt.TypeName, b.IsAvailable
FROM
    Library as L inner join Books as b on b.LibraryId = l.Id
WHERE b.IsAvailable = '1' and (
    SELECT count(distinct bt.Language) /* distinct may not be strictly necessary */
    FROM Books as b2 inner join BookType as bt on bt.Id = b2.BookTypeId
    WHERE b2.Id = b.Id and bt.Language in ('Bookname1_FR', 'Bookname2_EN')
) = 2