无法使用包含子查询的查询创建视图,我该怎么办?

时间:2014-04-17 08:45:08

标签: mysql sql

我想在数据库中为表创建一个视图,这样我就可以更容易地在连接中使用它。表UserSettings看起来像这样:

mysql> desc UserSettings;  -- cut the output for readability 
+-----------+---------------------
| Field     | Type                
+-----------+---------------------
| userID    | bigint(20) unsigned 
| timestamp | timestamp           
| settingID | text                
| setting   | text                
+-----------+---------------------
4 rows in set (0.00 sec)

在其中我们存储用户设置的每个更新。现在我想为这个表创建一个视图,其中包含每个用户的最新设置。所以我希望视图包含标有*的行:

mysql> select * from UserSettings;
+--------+---------------------+-----------------------+---------+
| userID | timestamp           | settingID             | setting |
+--------+---------------------+-----------------------+---------+
|    123 | 2014-04-16 12:08:30 | settings.warnings_off | 1       |
|    123 | 2014-04-16 12:18:56 | settings.warnings_off | 0       |
|    123 | 2014-04-17 06:42:08 | settings.warnings_off | 1       |
|    123 | 2014-04-17 06:49:08 | settings.warnings_off | 0       | *
|    911 | 2014-04-17 06:49:33 | settings.warnings_off | 1       | *
|    123 | 2014-04-17 10:04:12 | settings.test         | fooo    | 
|    123 | 2014-04-17 10:04:22 | settings.test         | bar     | *
|    911 | 2014-04-17 10:07:40 | settings.test         | bar     | *
+--------+---------------------+-----------------------+---------+
8 rows in set (0.00 sec)

我可以使用包含子查询的查询来执行此操作:

mysql> SELECT us.* 
    -> FROM  UserSettings us INNER JOIN (
    ->     SELECT userID, settingID, max(timestamp) as timestamp 
    ->     from UserSettings 
    ->     group by userID, settingID) ts ON ts.userID = us.userID AND 
    ->   ts.settingID = us.settingID AND ts.timestamp = us.timestamp;
+--------+---------------------+-----------------------+---------+
| userID | timestamp           | settingID             | setting |
+--------+---------------------+-----------------------+---------+
|    123 | 2014-04-17 10:04:22 | settings.test         | bar     |
|    123 | 2014-04-17 06:49:08 | settings.warnings_off | 0       |
|    911 | 2014-04-17 10:07:40 | settings.test         | bar     |
|    911 | 2014-04-17 06:49:33 | settings.warnings_off | 1       |
+--------+---------------------+-----------------------+---------+
4 rows in set (0.00 sec)

但是,在ERROR 1349 (HY000): View's SELECT contains a subquery in the FROM clause中使用上述查询时,我收到错误CREATE VIEW CurrentUserSettings AS <THE QUERY ABOVE>

有没有办法创建UserSettings表的视图,显示与上述查询相同的数据?也许以某种方式使用HAVING

2 个答案:

答案 0 :(得分:2)

扩展我的评论: -

CREATE VIEW latest_timestamp AS SELECT userID, settingID, max(timestamp) as timestamp 
    from UserSettings 
    group by userID, settingID;

CREATE VIEW latest_timestamp AS SELECT us.* 
FROM  UserSettings us 
INNER JOIN latest_timestamp ts 
ON ts.userID = us.userID AND 
ts.settingID = us.settingID 
AND ts.timestamp = us.timestamp;

另一种选择是(ab)使用GROUP_CONCAT函数。我并不热衷于这样做,如果字段可以包含NULL,则存在问题,并且需要将整数转换为字符字段。

假设你想要的字段叫做field1,field2和field3,那么: -

SELECT us.userID,
        us.settingID,
        SUBSTRING_INDEX(GROUP_CONCAT(us.field1 ORDER BY timestamp DESC SEPARATOR '|~|~'), '|~|~', 1),
        SUBSTRING_INDEX(GROUP_CONCAT(us.field2 ORDER BY timestamp DESC SEPARATOR '|~|~'), '|~|~', 1),
        SUBSTRING_INDEX(GROUP_CONCAT(us.field3 ORDER BY timestamp DESC SEPARATOR '|~|~'), '|~|~', 1)
FROM  UserSettings us 
GROUP BY us.userID, us.settingID;

这可以通过将一个字段的所有值连接成一个,按时间戳降序排序,并在它们之间有一个分隔符(不在任何字段中),然后使用SUBSTRING_INDEX将字段设置为第一个分隔符。

答案 1 :(得分:1)

像Kickstart建议的那样,喜欢这个

首先,在视图中创建子查询

CREATE VIEW subqueryview as 
SELECT userID, settingID, max(timestamp) as timestamp 
from UserSettings group by userID, settingID;

然后您可以使用视图创建视图。

CREATE VIEW finalview AS 
SELECT us.* 
FROM UserSettings us 
-- Here you now use the view created.
INNER JOIN  subqueryview ts 
ON ts.userID = us.userID 
AND ts.settingID = us.settingID 
AND ts.timestamp = us.timestamp;