让这个查询做它应该做的事情

Posted

技术标签:

【中文标题】让这个查询做它应该做的事情【英文标题】:getting this query to do what its supposed to do 【发布时间】:2017-10-05 13:58:51 【问题描述】:

所以,我认为这个问题只需要当前或过去以“哈利波特”为书名的会员。如果有一个成员仅在 4 本书中的当前或历史 2 中签出,则不应输出该成员,如果该成员仅在当前的 4 本书中签出 2 本书,则也不应输出该成员。但是,如果一个成员当前或已经签出了标题为“哈利波特”的所有书籍,则无论所有书籍当前是当前还是过去,都应该退出该成员。但是,如果所有的书都是当前或过去的,它应该输出那个成员。

问题来了:

列出当前或过去借阅图书馆中标题为“哈利波特”的所有书籍的成员的会员 ID、名字和姓氏。如果任何此类书籍有多个副本,则会员必须至少借阅每本此类书籍的副本。

代码:

CREATE TABLE Book
    (bookID INT,
    ISBN INT,
    title varchar (60),
    author  varchar (20),
    publish_year INT,
    category varchar(20),
    PRIMARY KEY (bookID));  

CREATE TABLE Member
    (memberID INT,
    lastname varchar (20),
    firstname varchar (20),
    address varchar(20),
    phone_number INT,   
    limit_ INT,
    PRIMARY KEY (memberID));

CREATE TABLE CurrentLoan
    (memberID INT ,
    bookID INT,
    loan_date DATE,
    due_date DATE,
    PRIMARY KEY (memberID, bookID),
    FOREIGN KEY (memberID) REFERENCES Member(memberID),
    FOREIGN KEY (bookID) REFERENCES Book(bookID));

CREATE TABLE History
    (memberID INT,
    bookID INT,
    loan_date DATE,
    return_date DATE,
    PRIMARY KEY (memberID, bookID, loan_date),
    FOREIGN KEY (memberID) REFERENCES Member(memberID),
    FOREIGN KEY (bookID) REFERENCES Book(bookID));

INSERT INTO Book VALUES (10, 7771452369, 'XML and XQuery', 'Author Le', 2017, 'reference');
INSERT INTO Book VALUES (11, 8881245525, 'XQuery: The XML Query Language', 'Jack Se', 2017, 'reference');
INSERT INTO Book VALUES (12, 9991123546, 'Yellow Bird', 'Jake Red', 2014, 'reference');
INSERT INTO BOOK VALUES (13, 1212121212, 'The Giving Tree', 'Shel Silverstein', 1964, 'fiction');
INSERT INTO BOOK VALUES (14, 2121212121, 'Gone Fishing', 'Shel Silverstein', 1964, 'reference');
INSERT INTO BOOK VALUES (15, 1313131313, 'The Lazy Dog', 'Jake Red', 2016, 'childrens');
INSERT INTO BOOK VALUES (16, 3131313131, 'The Red Bird', 'Jake Red', 2016, 'childrens');
INSERT INTO BOOK VALUES (17, 1414141414, 'The Very Blue Boy', 'Ben Jen', 2006, 'fiction');
INSERT INTO Book VALUES (18, 1113312336, 'Harry Potter 1', 'J. K. Rowling', 2000, 'fiction');
Insert INTO Book VALUES (19, 1113331142, 'Harry Potter 1', 'J. K. Rowling', 2000, 'fiction');
INSERT INTO Book VALUES (20, 2221257787, 'The Real Harry Potter 2', 'J. K. Rowling', 2009, 'fiction');
INSERT INTO Book VALUES (21, 2221254896, 'The Fake Harry Potter 3', 'J. K. Rowling', 2010, 'fiction');
INSERT INTO Book VALUES (22, 2221254896, 'The Fake Harry Potter 3', 'J. K. Rowling', 2010, 'fiction');
INSERT INTO Book VALUES (23, 2221254896, 'The Fake Harry Potter 4', 'J. K. Rowling', 2012, 'fiction');
INSERT INTO Book VALUES (24, 2221254896, 'The Fake Harry Potter 4', 'J. K. Rowling', 2012, 'fiction');

INSERT INTO Member VALUES (001, 'Lee', 'Nancy', 'Brownlea Drive', 1254896325, 10);
INSERT INTO Member VALUES (002, 'Le', 'Ray', '10th Street', 1234561256, 2);
INSERT INTO Member VALUES (003, 'Kan', 'Charlie', '5th Street', 1234567236, 8);
INSERT INTO Member VALUES (004, 'Brown', 'Joe', 'Elm Street', 1234567845, 9);
INSERT INTO Member VALUES (005, 'Smith', 'John', '33 East', 1234567890, 3);
INSERT INTO Member VALUES (006, 'Khang', 'Nkaujyi', '358 Spencer', 2145345625, 5);

INSERT INTO CurrentLoan VALUES (001, 10, '13-SEP-17', '14-NOV-17');
INSERT INTO CurrentLoan VALUES (001, 11, '13-SEP-17', '14-NOV-17');
INSERT INTO CurrentLoan VALUES (001, 18, '13-SEP-17', '14-NOV-17');
INSERT INTO CurrentLoan VALUES (001, 20, '13-SEP-17', '14-NOV-17');
INSERT INTO CurrentLoan VALUES (001, 22, '13-SEP-17', '14-NOV-17');
INSERT INTO CurrentLoan VALUES (001, 24, '13-SEP-17', '14-NOV-17');
INSERT INTO CurrentLoan VALUES (002, 21, '14-FEB-17', '12-MAR-17');
INSERT INTO CurrentLoan VALUES (002, 23, '14-FEB-17', '12-MAR-17');

INSERT INTO History VALUES (002, 10, '03-JAN-16', '25-MAY-16');
INSERT INTO History VALUES (002, 11, '03-JAN-16', '25-MAY-16');
INSERT INTO History VALUES (002, 12, '03-JAN-16', '25-MAY-16');
INSERT INTO History VALUES (002, 18, '03-JAN-16', '25-MAY-16');
INSERT INTO History VALUES (002, 20, '03-JAN-16', '25-MAY-16');
INSERT INTO History VALUES (002, 13, '03-JAN-16', '25-MAY-16');
COMMIT;

此查询将输出 memberID 2,因为该成员已将所有标题为“哈利波特”的书在当前或历史中签出。但是,memberID 1 没有,它应该输出它,因为它当前包含所有标题为“哈利波特”的书。

查询:

SELECT Member.memberID, lastname, firstname
FROM Member
INNER JOIN CurrentLoan ON Member.memberID = CurrentLoan.memberID
INNER JOIN Book ON CurrentLoan.bookID = Book.bookID
WHERE Book.title like '%Harry Potter%'
intersect
SELECT Member.memberID, lastname, firstname
FROM Member
INNER JOIN History ON Member.memberID = History.memberID
INNER JOIN Book ON History.bookID = Book.bookID
WHERE Book.title like '%Harry Potter%';

【问题讨论】:

感谢您为您的数据提供 DDL 和 DML 语句。 【参考方案1】:

您可以使用GROUP BYHAVING 来检查“所有”书籍。

WITH cte AS (
    SELECT *
    FROM Book
    WHERE  title LIKE '%Harry Potter%'
), cte2 AS (
   SELECT memberId
   FROM (SELECT l.*, b.title
         FROM currentLoan l
         JOIN Book b  ON b.bookId = l.bookId
         UNION ALL
         SELECT l.*, b.title
         FROM History l
         JOIN Book b  ON b.bookId = l.bookId) sub
   WHERE bookID IN (SELECT bookID FROM cte)
   GROUP BY memberId
   HAVING COUNT(DISTINCT(title)) = (SELECT COUNT(DISTINCT title) FROM cte)
)
SELECT memberID, firstname,  lastname
FROM Member
WHERE memberId IN (SELECT memberId FROM cte2);

Rextester Demo

编辑:

更简单的形式:

SELECT memberID, firstname,  lastname
FROM (
    SELECT  b.title, m.memberID, m.firstname,  m.lastname
    FROM currentLoan l
    JOIN Book b  ON b.bookId = l.bookId
    JOIN member m ON l.memberId = m.memberId
    WHERE b.bookID IN (SELECT bookId FROM Book WHERE title LIKE '%Harry Potter%')
    UNION ALL
    SELECT  b.title, m.memberID, m.firstname,  m.lastname
    FROM History l
    JOIN Book b  ON b.bookId = l.bookId
    JOIN member m ON l.memberId = m.memberId
    WHERE b.bookID IN (SELECT bookId FROM Book WHERE title LIKE '%Harry Potter%')
    ) sub
GROUP BY memberID, firstname,  lastname
HAVING COUNT(DISTINCT(title))= 
      (SELECT COUNT(DISTINCT title) FROM Book WHERE title LIKE '%Harry Potter%');

Rextester Demo2

【讨论】:

这个似乎可行,但我只需要成员 ID、名字和姓氏。但是,什么是 WITH 和 cte?我对 WITH 或 cte 一无所知? CTE 是组织代码的好方法。与子查询相同。 好的,希望我们能在本学期晚些时候讨论这个问题。但是,对于这个查询,我只需要 memberID、firtname 和 lastname。 @tubvajlis 我提供了没有 CTE 的版本。【参考方案2】:

INTERSECT 只会返回在两个查询中都出现的 rwos - 因此您只会得到当前借出匹配书籍并且过去也借出匹配书籍的人。

你想要这样的东西:

查询 1

WITH matching_books AS (
  SELECT BookID, ISBN
  FROM   book
  WHERE  title LIKE '%Harry Potter%'
)
SELECT MemberId,
       Firstname,
       lastname
FROM   Member
WHERE  MemberID IN (
         SELECT MemberID
         FROM   ( SELECT MemberID, BookID
                  FROM   CurrentLoan
                  UNION ALL
                  SELECT MemberID, BookID
                  FROM   History
                ) l
                INNER JOIN matching_books b
                ON ( l.bookId = b.bookId )
         GROUP BY MemberID
         HAVING COUNT( DISTINCT b.ISBN ) = ( SELECT COUNT( DISTINCT isbn ) FROM matching_books )
       )

Results

没有结果 - 这是因为没有用户取出所有具有唯一 ISBN 的哈利波特图书的所有图书。您可以重做查询以比较标题(而不是 ISBN),它会给出您正在寻找的结果,但这不能保证是唯一的。

【讨论】:

all the book with title "Harry Potter" => all 不,因为当我删除“INSERT INTO History VALUES (002, 18, '03-JAN-16', '25-MAY-16');”输出不应该有 memberId 2 的任何内容,它应该只有 memberID 1 的输出。因为只有 memberID 1 的所有书籍标题都为“哈利波特”。 @MTO 请问它如何处理all 书籍? Wrong result demo @tubvajlis 更新 @MT0 好的,会试试的。

以上是关于让这个查询做它应该做的事情的主要内容,如果未能解决你的问题,请参考以下文章

Codeigniter 表单结果作为另一个表单输入值。第二个表格没有做它应该做的事情

如何配置 Vue 路由器以响应查询字符串?

Thread.sleep(x) 没有做它必须做的事情[重复]

如何让 JsHint sbt 插件更有用?

这个javascript的“rel”应该是什么?

阻止 jQuery 做它的事情?