2014-01-24 50 views
1

我有三個表:活動,動作(每個動作是一個活動的執行)和照片(每個動作都可以有附加的照片)。一個SQLite查詢中的兩個和三個表

這裏是an SQL Fiddle for this

現在我想要以降序檢索活動,並且對於每個活動我都希望花費在其上的總時間和附加的總照片。使用上次操作的停止時間計算的活動順序。

例如,對於以下數據

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 

如何更改我的查詢以獲得我想要的?

回答

3

THANK YOU for set up SQL Fiddle。這使事情變得更容易)。

您正朝着正確的方向前進 - 您可能需要添加的所有內容都是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 

(和working result fiddle

具體做法是:

  1. 你被所有列分組(在內部查詢中)。在這種情況下,您要麼想要DISTINCT(概念上/邏輯上),要麼將查詢更改爲更小更好。請注意,通過按照我在這裏的表格進行彙總,指標更有可能被使用。
  2. 您正在按編號列分組:總是拼出您想要的列。在極端情況下,如果有人更改SELECT列表中列的排列順序,但是不是,GROUP BY,那麼結果可能會發生變化......以您不期望的方式發生,並且而不是會收到錯誤。
  3. 你的內部查詢有一個ORDER BY。這是非常不必要的,並且迫使引擎做額外的工作。
  4. 您的外部GROUP BY只引用了一列,但有一列未彙總/分組。在這種情況下它給出了正確的結果,但這是一個危險的特徵;如果有多個可能的值,選擇哪一個值是不可確定的。避免這種情況。
  5. 首選SQL標準功能(除非出於特定性能原因) - IFNULL()不適用於所有平臺,但COALESCE。除了日期/時間數學(通常依賴於RDBMS),這個查詢可以在所有平臺上工作。

(順便說一句,我對SQLite的缺乏日期/時間/時間戳類型的惱火,但因爲這是幾乎沒有你的錯......)

+0

感謝您指出查詢中的問題。他們對我來說很合理。不幸的是,我認爲通過'Actions.totalSeconds'命令是錯誤的。它確實給出了測試數據的所需結果,但是一個行動或活動的持續時間與訂單無關。活動停止的時間是相關的(最後停止應該是結果中的第一個) – Bobrovsky

+0

所以,你知道,這是你第一次給出排序應該是什麼;這就是爲什麼@Ondemannen和我給出了我們所做的答案。更新答案。 –

+0

我確實說過「使用它的最後一個動作的停止時間來計算一個活動的順序」,但可能並不那麼明顯。無論如何,感謝您的更新,它解決了這個問題。你不僅解決了這個問題,而且給出了一些很好的建議。謝謝。 – Bobrovsky

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那麼您將收到相同的結果。

+0

不幸的是,這是不正確的。秒與我想要得到的順序絕對不相關。 – Bobrovsky

+0

如何將*秒*更改爲* cnt *? – Ondemannen

+0

它們也與訂單無關。 – Bobrovsky