              :id nil
              :description nil}))
 
+(defn is-special-aggregation?
+  "Is this aggregation clause a 'special' case such as `sum`?"
+  [aggregation]
+  (match (first aggregation)
+    "rows" true
+    "sum" true
+    :else false))
+
+(defn apply-special-aggregation [{:keys [source_table table aggregation] :as query}]
+  (case (first aggregation)
+    "rows" (->> (sel :many Field :table_id source_table) ; aggregation: ["rows"] just means return all rows
+                (map (partial annotate-column table)))
+    "sum" (let [{:keys [name] :as field} (annotate-column-with-id table (second aggregation))]
+            (->> (assoc field
+                       :name (format "Sum (%s)" name)
+                       :keyword :sum
+                       :alias :sum
+                       :select (format "SUM(\"%s\".\"%s\")" (:name table) name))
+                 vector))))
+
 (defn get-columns
-  "Return an array of column info dictionaries for query."
+  "Return an array of column info dictionaries for QUERY."
   [{:keys [source_table table breakout aggregation] :as query}]
-  (if (= aggregation ["rows"]) (->> (sel :many Field :table_id source_table) ; aggregation: ["rows"] just means return all rows
-                                    (map (partial annotate-column table)))
+  {:post [sequential?]}
+  (if (is-special-aggregation? aggregation) (apply-special-aggregation query)
       (->> (concat breakout aggregation)
            (filter identity)
            (map (fn [column]

          :database (:db (-> (:source_table <>)
                             (hydrate :db)))
          :columns (get-columns <>)
          :columns-by-name (->> (:columns <>)
                                (map (fn [{:keys [keyword] :as col}]
                                       {keyword col}))
                                (reduce merge {}))
          :columns-by-id (->> (:columns <>)
                              (filter :id)
                              (map (fn [{:keys [id] :as col}]
                                     {id col}))
                              (reduce merge {}))
          :ordered-columns (map :keyword (:columns <>))
          :ordered-aliases (map #(keyword (:alias %)) (:columns <>))
          :sql (->> <>

    {:status :completed
     :row_count (count results)
     :data {:rows (->> results
                       (mapv #(mapv % (:ordered-aliases query-dict)))
                       (mapv format-result))
            :columns (mapv :name columns)
            :cols (mapv column-name->column
                        ordered-columns)}}))
