如何修复以下SQL查询?

时间:2015-11-13 01:27:29

标签: mysql

我创建了一个包含6个表(6个实体)的数据库,其中3个表被称为" Sessions"," Reviews"和" Persons"。他们的规格如下:

CREATE TABLE Sessions(
s_tutorID VARCHAR(6),
startTime DATETIME,
location VARCHAR(140) NOT NULL,
language VARCHAR(20) NOT NULL,
s_studentID VARCHAR(6),
paidOrNot BINARY(1) NOT NULL, 
reviewedOrNot BINARY(1), 
INDEX (startTime),
INDEX (language),
PRIMARY KEY (s_tutorID, startTime),
FOREIGN KEY (s_tutorID) REFERENCES TutorsAddedLanguage(tutorID) ON DELETE NO ACTION,
FOREIGN KEY (s_studentID) REFERENCES StudentsAddedPayment(studentID) ON DELETE NO ACTION,
CONSTRAINT s_tutorIDform CHECK (s_tutorID REGEXP '^[a-z]{2}\d{4}$' > 0),
CONSTRAINT s_studentIDform CHECK (s_studentID REGEXP '^[a-z]{2}\d{4}$' > 0));


CREATE TABLE Persons(
ID VARCHAR(6),
name VARCHAR(30) NOT NULL, 
photo VARCHAR(30) NOT NULL, 
department VARCHAR(30) NOT NULL, 
graduatingYear YEAR(4) NOT NULL,
gender BINARY(1) NOT NULL,
selfIntro VARCHAR(1000) NOT NULL,
PRIMARY KEY (ID),
CONSTRAINT IDform CHECK (ID REGEXP '^[a-z]{2}\d{4}$' > 0));

CREATE TABLE Reviews(
r_tutorID VARCHAR(6),
r_sessionStartTime DATETIME,
r_studentID VARCHAR(6) NOT NULL,
r_sessionLanguage VARCHAR(20) NOT NULL,
-- score DECIMAL(2,1) NOT NULL,
score INT NOT NULL,
givenTime DATETIME NOT NULL,
comments VARCHAR(1000),
PRIMARY KEY (r_tutorID, r_sessionStartTime),
FOREIGN KEY (r_tutorID) REFERENCES Sessions(s_tutorID),-- ON UPDATE CASCADE,
FOREIGN KEY (r_studentID) REFERENCES Sessions(s_studentID),-- ON UPDATE CASCADE,
FOREIGN KEY (r_sessionStartTime) REFERENCES Sessions(startTime),-- ON UPDATE CASCADE,
FOREIGN KEY (r_sessionLanguage) REFERENCES Sessions(language),
CONSTRAINT r_studentIDform CHECK (r_studentID REGEXP '^[a-z]{2}\d{4}$' > 0),
CONSTRAINT r_tutorIDform CHECK (r_tutorID REGEXP '^[a-z]{2}\d{4}$' > 0),
CONSTRAINT scoreform CHECK (score <= 5 AND score >= 0));

然后,我在每个表中插入了一些假数据,确保每个数据条目之间的所有逻辑都是正确的。

现在,我想编写一个查询,选择2016-01-03上的所有会话,会话的语言是ENG(英语),Sessions.paidOrNot =&#39; 0&#39; 。输出应该是一个包含以下列的表:date,starttime,endtime,location,Tutor_name,Tutor_email。

我编写了以下SQL查询:

SELECT DATE_FORMAT(S.startTime,'%d %b %Y') AS date,      
DATE_FORMAT(S.startTime,'%h:%i %p') AS starttime,    
DATE_FORMAT(S.startTime + INTERVAL 30 MINUTE,'%h:%i %p') AS endtime, 
S.location, 
P.name AS Tutor_name, 
CONCAT(P.ID, '@gmail.com') AS Tutor_email 
FROM Sessions S, Persons P 
WHERE DATE_FORMAT(S.startTime,'%Y-%m-%d') = '2016-01-03' 
AND S.paidOrNot = '0' 
AND S.s_tutorID = P.ID 
AND S.language = 'ENG' 
ORDER BY S.startTime ASC;

输出表如下:

+-------------+-----------+----------+----------+------------------+---------------------+
| date        | starttime | endtime  | location | Tutor_name       | Tutor_email         |
+-------------+-----------+----------+----------+------------------+---------------------+
| 03 Jan 2016 | 09:00 AM  | 09:30 AM | AlexHall   | Mike Connolly    | mc9514@gmail.com |
| 03 Jan 2016 | 09:30 AM  | 10:00 AM | Winson     | Choko Cahill     | cc6624@gmail.com |
| 03 Jan 2016 | 10:00 AM  | 10:30 AM | Turner   | Mike Connolly    | mc9514@gmail.com |
| 03 Jan 2016 | 02:00 PM  | 02:30 PM | GrandHall   | Milenka Caterini | mc1894@gmail.com |
+-------------+-----------+----------+----------+------------------+---------------------+
4 rows in set (0.10 sec)

现在,我想在上面的查询结果表中添加另一个列,一个名为&#34; Average_Review_Score&#34;的列,它在评论中获取此元组的Tutor_name的Reviews.score的平均值表格,分数必须是同一种语言的分数(ENG)。

例如,评论表如下所示:

mysql> select * from Reviews order by r_tutorID;
+------------+---------------------+--------------+-------------------+-------+---------------------+-----------------------------------------------------------------------------------------+
| r_tutorID | r_sessionStartTime  | r_studentID | r_sessionLanguage | score | givenTime           | comments                                                                                |
+------------+---------------------+--------------+-------------------+-------+---------------------+-----------------------------------------------------------------------------------------+
| ah0133     | 2015-10-02 15:00:00 | jc3323       | JAP               |     4 | 2015-10-02 18:55:33 | oh yeah!                                                                                |
| ah0133     | 2015-10-08 12:00:00 | mc9514       | JAP               |     4 | 2015-10-10 10:59:39 | NULL                                                                                    |
| cc6624     | 2015-09-13 20:00:00 | ah0133       | ENG               |     4 | 2015-10-01 06:38:52 | Choko did a good job helping me with English writing. But he was late for 10 minutes... |
| cc6624     | 2015-10-08 13:00:00 | ah0133       | ENG               |     0 | 2015-10-09 18:49:29 | The tutor did not show up at all                                                        |
| jc3323     | 2015-10-08 12:00:00 | as3699       | SPA               |     3 | 2015-10-08 12:32:41 | NULL                                                                                    |
| jc3323     | 2015-10-08 13:00:00 | es4937       | SPA               |     1 | 2015-10-09 16:01:17 | bad                                                                                     |
| mc1894     | 2015-10-01 12:00:00 | cc6624       | SPA               |     4 | 2015-10-01 12:35:08 | Good session, but I dont think its really helpful to improve my Spanish class grade!    |
| mc1894     | 2015-10-01 13:00:00 | as3699       | SPA               |     3 | 2015-10-02 12:00:00 | fair                                                                                    |
| mc9514     | 2015-10-02 11:30:00 | ep6229       | ENG               |     5 | 2015-11-04 14:22:01 | NULL                                                                                    |
| mc9514     | 2015-10-03 10:00:00 | as3699       | SPA               |     5 | 2015-10-03 11:13:31 | oh my god                                                                               |
| mc9514     | 2015-10-03 12:00:00 | cc6624       | LAT               |     3 | 2015-10-04 23:45:17 | enough                                                                                  |
| mc9514     | 2015-11-09 19:30:00 | pd0039       | ENG               |     2 | 2015-11-09 22:49:13 | not vey helpful                                                                         |
| pd0039     | 2015-10-09 12:00:00 | nm3384       | FRE               |     3 | 2015-10-11 03:14:36 | NULL                                                                                    |
+------------+---------------------+--------------+-------------------+-------+---------------------+-----------------------------------------------------------------------------------------+
13 rows in set (0.09 sec)

以前的SQL查询给了我4个会话,如上所列,我只是再次把它放在这里:

+-------------+-----------+----------+----------+------------------+---------------------+
| date        | starttime | endtime  | location | Tutor_name       | Tutor_email         |
+-------------+-----------+----------+----------+------------------+---------------------+
| 03 Jan 2016 | 09:00 AM  | 09:30 AM | AlexHall   | Mike Connolly    | mc9514@gmail.com |
| 03 Jan 2016 | 09:30 AM  | 10:00 AM | MidCafe     | Choko Cahill     | cc6624@gmail.com |
| 03 Jan 2016 | 10:00 AM  | 10:30 AM | Turner   | Mike Connolly    | mc9514@gmail.com |
| 03 Jan 2016 | 02:00 PM  | 02:30 PM | GrandHall   | Milenka Caterini | mc1894@gmail.com |
+-------------+-----------+----------+----------+------------------+---------------------+

现在,我想添加一个列&#34; Average_Review_Score&#34;。例如,对于Mike Connolly教授的第一个ENG会话(ID:mc9514),&#34; Average_Review_Score&#34;应该是(5 + 2)/ 2 = 3.5,因为在如上所示的评论表中,这位导师Mike Connolly(ID:mc9514)到目前为止收到了4条评论,在4条评论中,其中2条评论是关于& #34; ENG&#34; (Reviews.r_sessionLanguage):一个评论得分为5,另一个评论得分为2.同样我们想找到&#34; Average_Review_Score&#34;对于所有其他两位导师:Choko Cahill(ID:cc6624)和Milenka Caterini(身份证号码:mc1894)。

为了达到这个目的,我写了以下查询:

SELECT DATE_FORMAT(S.startTime,'%d %b %Y') AS date,      
DATE_FORMAT(S.startTime,'%h:%i %p') AS starttime,    
DATE_FORMAT(S.startTime + INTERVAL 30 MINUTE,'%h:%i %p') AS endtime, 
S.location, 
P.name AS Tutor_name, 
CONCAT(P.ID, '@gmail.com') AS Tutor_email, 
AVG(R.score) AS Average_Review_Score
FROM Sessions S, Persons P, Reviews R
WHERE DATE_FORMAT(S.startTime,'%Y-%m-%d') = '2016-01-03' 
AND S.paidOrNot = '0' 
AND S.s_tutorID = P.ID 
AND S.language = 'ENG' 
AND R.r_tutorID = S.s_tutorID 
AND R.r_sessionLanguage = S.language
ORDER BY S.startTime ASC;

但是,上面的查询只给我一个会话:

+-------------+-----------+----------+----------+--------------+------------------+----------------------+
| date        | starttime | endtime  | location | Tutor_name   | Tutor_email      | Average_Review_Score |
+-------------+-----------+----------+----------+--------------+------------------+----------------------+
| 03 Jan 2016 | 09:30 AM  | 10:00 AM |  MidCafe    | Choko Cahill | cc6624@gmail.com |               3.0000 |
+-------------+-----------+----------+----------+--------------+------------------+----------------------+
1 row in set (0.09 sec)

那我该怎么写这个查询呢?这里有什么问题?

2 个答案:

答案 0 :(得分:1)

最好使用&#34;加入&#34;加入你的表格,然后使用&#34; group by&#34;创建聚合。
选择......,
AVG(R.score)AS Average_Review_Score
来自会议S
内部联接人员P在S.s_tutorID = P.ID上 左连接评论R on R.r_tutorID = S.s_tutorID AND R.r_sessionLanguage = S.language
在哪里...
GROUP BY ....
ORDER BY S.startTime ASC;

答案 1 :(得分:0)

检查现有查询的一部分,但格式化以突出显示一些建议的更改:

...
FROM Sessions S
   , Persons P
   , Reviews R
WHERE DATE_FORMAT(S.startTime, '%Y-%m-%d') = '2016-01-03'
      AND S.paidOrNot = '0'
      AND S.s_tutorID = P.ID <<<<<<<<<<<<<<<< join (2 tables S & P)
      AND S.language = 'ENG'
      AND R.r_tutorID = S.s_tutorID  <<<<<<<< join (2 tables R & S)
      AND R.r_sessionLanguage = S.language << join (2 tables R & S)

我建议你停止在FROM子句中使用逗号。这有助于您采用更健壮的方法来定义连接,并将where子句简化为额外的好处。

我还建议你不要在where子句中使用函数DATE_FORMAT()。保持数据不变更有效。而是使用&gt; =与&lt;的组合。过滤当天内所有时间戳的值。

...
FROM Sessions S
      INNER JOIN Persons P ON S.s_tutorID = P.ID
      INNER JOIN Reviews R ON R.r_tutorID = S.s_tutorID AND R.r_sessionLanguage = S.language
WHERE S.startTime >= '2016-01-03'
      AND S.startTime < '2016-01-04'
      AND S.paidOrNot = '0'
      AND S.language = 'ENG'

您之前的单行结果表明INNER JOIN限制性太强,因此可能需要使用LEFT OUTER JOIN。然后需要一个GROUP BY子句,其中应该包含select子句的“非聚合”列[没有函数的那些列,如SUM()COUNT()AVG()]

SELECT
      DATE_FORMAT(S.startTime, '%d %b %Y') AS date
    , DATE_FORMAT(S.startTime, '%h:%i %p') AS starttime
    , DATE_FORMAT(S.startTime + INTERVAL 30 MINUTE, '%h:%i %p') AS endtime
    , S.location
    , P.NAME AS Tutor_name
    , CONCAT (P.ID, '@gmail.com') AS Tutor_email
    , AVG (R.score) AS Average_Review_Score
FROM Sessions S
      INNER JOIN Persons P ON S.s_tutorID = P.ID
      LEFT OUTER JOIN Reviews R ON R.r_tutorID = S.s_tutorID AND R.r_sessionLanguage = S.language
WHERE S.startTime >= '2016-01-03'
      AND S.startTime < '2016-01-04'
      AND S.paidOrNot = '0'
      AND S.language = 'ENG'
GROUP BY
      DATE_FORMAT(S.startTime, '%d %b %Y')
    , DATE_FORMAT(S.startTime, '%h:%i %p')
    , S.location
    , P.NAME
    , P.ID
ORDER BY
      S.startTime ASC;