我有三个表:活动,动作(每个动作是一个活动的执行)和照片(每个动作都可以附加照片)。
现在我想按降序检索活动,对于每项活动,我想要花费在其上的总时间和附加到它的总照片。使用其最后一次操作的停止时间计算的活动顺序。
例如,对于以下数据
activities
------------------
_id | title
------------------
1 | Activity 1
2 | Activity 2
3 | Activity 3
4 | Activity 4
actions
-------------------------------------------------------------
_id | activity_id | date_started | date_stopped
-------------------------------------------------------------
1 | 1 | 2014-01-23 20:45:03 | 2014-01-23 20:45:24
2 | 2 | 2014-01-23 20:45:27 | 2014-01-23 20:45:29
3 | 3 | 2014-01-23 20:45:31 | 2014-01-23 20:45:43
4 | 1 | 2014-01-23 20:45:46 | 2014-01-23 20:45:48
5 | 4 | 2014-01-23 20:45:50 | 2014-01-23 20:46:19
photos
--------------------------------------------------------
_id | action_id | date_taken | path
--------------------------------------------------------
1 | 1 | 2014-01-23 20:45:11 | 758712034.jpg
2 | 1 | 2014-01-23 20:45:21 | 537444469.jpg
3 | 3 | 2014-01-23 20:45:39 | 28884579.jpg
4 | 5 | 2014-01-23 20:45:58 | 1519722792.jpg
5 | 5 | 2014-01-23 20:46:08 | 298808374.jpg
6 | 5 | 2014-01-23 20:46:15 | 2059925529.jpg
我希望通过此查询获取所需数据:
SELECT
activityId, title, sum(seconds) AS totalSeconds, sum(cnt) AS totalPhotos
FROM
(
SELECT
activities._id AS activityId, activities.title AS title,
actions._id AS actionId,
strftime("%s", ifnull(actions.date_stopped, 'now')) -
strftime("%s", actions.date_started) AS seconds,
count(photos._id) AS cnt
FROM
activities JOIN actions ON activities._id = actions.activity_id
LEFT OUTER JOIN photos ON photos.action_id = actions._id
GROUP BY 1,2,3,4
ORDER BY actionId DESC
)
GROUP BY 1
但不幸的是,它给出了这个结果:
activityId | title | totalSeconds | totalPhotos
--------------------------------------------------------
1 | Activity 1 | 23 | 2
2 | Activity 2 | 2 | 0
3 | Activity 3 | 12 | 1
4 | Activity 4 | 29 | 3
我试图得到这个(请参阅操作表中activity_id
的顺序):
activityId | title | totalSeconds | totalPhotos
--------------------------------------------------------
4 | Activity 4 | 29 | 3
1 | Activity 1 | 23 | 2
3 | Activity 3 | 12 | 1
2 | Activity 2 | 2 | 0
如何更改查询以获得我想要的内容?
答案 0 :(得分:3)
(感谢您设置SQL小提琴。这会让事情变得更轻松。)
您正朝着正确的方向前进 - 可能,您需要添加ORDER BY totalSeconds DESC
到查询的末尾。但是,您的查询有几个问题,并且在这些方面可能会更好:
SELECT Activities._id, Activities.title, Actions.totalSeconds, Actions.totalPhotos
FROM Activities
JOIN (SELECT Actions.activity_id,
SUM(STRFTIME("%s", COALESCE(Actions.date_stopped, 'now'))
- STRFTIME("%s", Actions.date_started)) AS totalSeconds,
SUM(COALESCE(Photos.photoCount, 0)) as totalPhotos,
MAX(COALESCE(Actions.date_stopped, DATETIME('now'))) as mostRecent
FROM Actions
LEFT JOIN (SELECT action_id, COUNT(*) as photoCount
FROM Photos
GROUP BY action_id) Photos
ON Photos.action_id = Actions._id
GROUP BY Actions.activity_id) Actions
ON Actions.activity_id = Activities._id
ORDER BY Actions.mostRecent DESC
具体做法是:
DISTINCT
(概念上/逻辑上),要么更好地将查询更改为更小的聚合。请注意,通过像我这里的表一样进行聚合,更有可能使用索引。SELECT
列表中列的排序,但不是 GROUP BY
,那么您的结果可能会以您不期望的方式发生变化......并且不会收到错误。ORDER BY
。这是非常不必要的,并且迫使引擎做额外的工作。GROUP BY
仅引用了一列,但有一列未汇总/分组。在这种情况下,它给出了正确的结果,但这是一个危险的特征;如果可能存在多个值,则选择哪个值是不可确定的。默认情况下避免这种情况。IFNULL()
并非在所有平台上,但COALESCE
是。除了日期/时间数学(通常依赖于RDBMS),此查询将适用于所有平台。(顺便说一句,我对SQLite缺少日期/时间/时间戳类型感到恼火,但这几乎不是你的错......)
答案 1 :(得分:1)
SELECT
activityId, title, sum(seconds) AS totalSeconds, sum(cnt) AS totalPhotos
FROM
(
SELECT
activities._id AS activityId, activities.title AS title,
actions._id AS actionId,
strftime("%s", ifnull(actions.date_stopped, 'now')) -
strftime("%s", actions.date_started) AS seconds,
count(photos._id) AS cnt
FROM
activities JOIN actions ON activities._id = actions.activity_id
LEFT OUTER JOIN photos ON photos.action_id = actions._id
GROUP BY 1,2,3,4
ORDER BY actionId DESC
)
GROUP BY 1
ORDER BY seconds DESC;
返回:
4|Activity 4|29|3
1|Activity 1|23|2
3|Activity 3|12|1
2|Activity 2|2|0
但我可能误解了这个问题,因为我添加的唯一内容是 ORDER BY秒DESC 行。如果您从秒改为 cnt ,那么您将收到相同的结果。