当我想在连接两个表后选择一些行时,我遇到了一些问题。
我有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结果?
答案 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