diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,6 +1,13 @@
 # Revision history for Selda
 
 
+## 0.3.2.0 -- 2018-08-07
+
+* Some aggregates are now nullable.
+* sum_ on an empty table doesn't crash anymore.
+* Aggregating over an empty selectValues doesn't crash anymore.
+
+
 ## 0.3.1.0 -- 2018-08-06
 
 * Minor API fix when defining table attributes.
diff --git a/selda.cabal b/selda.cabal
--- a/selda.cabal
+++ b/selda.cabal
@@ -1,5 +1,5 @@
 name:                selda
-version:             0.3.1.0
+version:             0.3.2.0
 synopsis:            Multi-backend, high-level EDSL for interacting with SQL databases.
 description:         This package provides an EDSL for writing portable, type-safe, high-level
                      database code. Its feature set includes querying and modifying databases,
diff --git a/src/Database/Selda.hs b/src/Database/Selda.hs
--- a/src/Database/Selda.hs
+++ b/src/Database/Selda.hs
@@ -47,8 +47,9 @@
   , (.==), (./=), (.>), (.<), (.>=), (.<=), like
   , (.&&), (.||), not_
   , literal, int, float, text, true, false, null_
-  , roundTo, length_, isNull, ifThenElse, matchNull
+  , roundTo, length_, isNull, ifThenElse, ifNull, matchNull
   , new, only
+  , Mappable (..)
     -- * Converting between column types
   , round_, just, fromBool, fromInt, toString
     -- * Inner queries
@@ -278,6 +279,29 @@
           -> Col s b
 matchNull nullvalue f x = ifThenElse (isNull x) nullvalue (f (cast x))
 
+-- | If the second value is Nothing, return the first value. Otherwise return
+--   the second value.
+ifNull :: SqlType a => Col s a -> Col s (Maybe a) -> Col s a
+ifNull nullvalue x = ifThenElse (isNull x) nullvalue (cast x)
+
+-- | Any container type which can be mapped over.
+--   Sort of like 'Functor', if you squint a bit.
+class Mappable f where
+  type Container f a
+  (.<$>) :: (SqlType a, SqlType b)
+         => (Col s a -> Col s b)
+         -> f s (Container f a)
+         -> f s (Container f b)
+infixl 4 .<$>
+
+instance Mappable Aggr where
+  type Container Aggr a = a
+  (.<$>) = liftAggr
+
+instance Mappable Col where
+  type Container Col a = Maybe a
+  f .<$> mx = cast (f (cast mx))
+
 -- | Any container type for which we can check object membership.
 class Set set where
   -- | Is the given column contained in the given set?
@@ -354,20 +378,20 @@
 count = aggr "COUNT"
 
 -- | The average of all values in the given column.
-avg :: (SqlType a, Num a) => Col s a -> Aggr s a
+avg :: (SqlType a, Num a) => Col s a -> Aggr s (Maybe a)
 avg = aggr "AVG"
 
 -- | The greatest value in the given column. Texts are compared lexically.
-max_ :: SqlOrd a => Col s a -> Aggr s a
+max_ :: SqlOrd a => Col s a -> Aggr s (Maybe a)
 max_ = aggr "MAX"
 
 -- | The smallest value in the given column. Texts are compared lexically.
-min_ :: SqlOrd a => Col s a -> Aggr s a
+min_ :: SqlOrd a => Col s a -> Aggr s (Maybe a)
 min_ = aggr "MIN"
 
 -- | Sum all values in the given column.
 sum_ :: forall a b s. (SqlType a, SqlType b, Num a, Num b) => Col s a -> Aggr s b
-sum_ = castAggr . aggr "SUM"
+sum_ = liftAggr (ifNull (0::Col s b) . cast) . aggr "SUM"
 
 -- | Round a value to the nearest integer. Equivalent to @roundTo 0@.
 round_ :: forall s a. (SqlType a, Num a) => Col s Double -> Col s a
diff --git a/src/Database/Selda/Column.hs b/src/Database/Selda/Column.hs
--- a/src/Database/Selda/Column.hs
+++ b/src/Database/Selda/Column.hs
@@ -81,27 +81,10 @@
   abs = liftC $ UnOp Abs
   signum = liftC $ UnOp Sgn
 
-instance {-# OVERLAPPING #-} (SqlType a, Num a) => Num (Col s (Maybe a)) where
-  fromInteger = literal . Just . fromInteger
-  (+) = liftC2 $ BinOp Add
-  (-) = liftC2 $ BinOp Sub
-  (*) = liftC2 $ BinOp Mul
-  negate = liftC $ UnOp Neg
-  abs = liftC $ UnOp Abs
-  signum = liftC $ UnOp Sgn
-
 instance Fractional (Col s Double) where
   fromRational = literal . fromRational
   (/) = liftC2 $ BinOp Div
 
-instance Fractional (Col s (Maybe Double)) where
-  fromRational = literal . Just . fromRational
-  (/) = liftC2 $ BinOp Div
-
 instance Fractional (Col s Int) where
   fromRational = literal . (truncate :: Double -> Int) . fromRational
-  (/) = liftC2 $ BinOp Div
-
-instance Fractional (Col s (Maybe Int)) where
-  fromRational = literal . Just . (truncate :: Double -> Int) . fromRational
   (/) = liftC2 $ BinOp Div
diff --git a/src/Database/Selda/Inner.hs b/src/Database/Selda/Inner.hs
--- a/src/Database/Selda/Inner.hs
+++ b/src/Database/Selda/Inner.hs
@@ -19,8 +19,10 @@
 --   converted into a non-aggregate column.
 newtype Aggr s a = Aggr {unAggr :: Exp SQL a}
 
-liftAggr :: (Exp SQL a -> Exp SQL b) -> Aggr s a -> Aggr s b
-liftAggr f = Aggr . f . unAggr
+-- | Lift a function over columns to aggregates.
+liftAggr :: (Col s a -> Col s b) -> Aggr s a -> Aggr s b
+liftAggr f = Aggr . unOne . f . One . unAggr
+  where unOne (One x) = x
 
 -- | Denotes an inner query.
 --   For aggregation, treating sequencing as the cartesian product of queries
diff --git a/src/Database/Selda/Query.hs b/src/Database/Selda/Query.hs
--- a/src/Database/Selda/Query.hs
+++ b/src/Database/Selda/Query.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE FlexibleContexts, OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts, OverloadedStrings, ScopedTypeVariables #-}
 -- | Query monad and primitive operations.
 module Database.Selda.Query
   ( select, selectValues, Database.Selda.Query.distinct
@@ -11,10 +11,13 @@
 import Database.Selda.Inner
 import Database.Selda.Query.Type
 import Database.Selda.SQL as SQL
-import Database.Selda.SqlType (SqlType)
+import Database.Selda.SqlType (SqlType, Lit (LNull), SqlTypeRep (..))
+import Database.Selda.SqlRow (SqlRow (nestedCols))
 import Database.Selda.Table
 import Database.Selda.Transform
 import Control.Monad.State.Strict
+import Data.Proxy
+import GHC.Generics (Rep)
 import Unsafe.Coerce
 
 -- | Query the given table.
@@ -27,11 +30,11 @@
 
 -- | Query an ad hoc table of type @a@. Each element in the given list represents
 --   one row in the ad hoc table.
-selectValues :: Relational a => [a] -> Query s (Row s a)
+selectValues :: forall s a. Relational a => [a] -> Query s (Row s a)
 selectValues [] = Query $ do
   st <- get
   put $ st {sources = sqlFrom [] EmptyTable : sources st}
-  return $ Many (repeat (Untyped $ Col "NULL"))
+  return $ Many (gNew (Proxy :: Proxy (Rep a)))
 selectValues (row:rows) = Query $ do
     names <- mapM (const freshName) firstrow
     let rns = [Named n (Col n) | n <- names]
diff --git a/src/Database/Selda/Table.hs b/src/Database/Selda/Table.hs
--- a/src/Database/Selda/Table.hs
+++ b/src/Database/Selda/Table.hs
@@ -39,7 +39,7 @@
 --   For example:
 --
 -- > data Person = Person
--- >   { id   :: Int
+-- >   { id   :: ID Person
 -- >   , name :: Text
 -- >   , age  :: Int
 -- >   , pet  :: Maybe Text
@@ -47,13 +47,13 @@
 -- >   deriving Generic
 -- >
 -- > people :: Table Person
--- > people = table "people" [name :- autoPrimary]
+-- > people = table "people" [pId :- autoPrimary]
+-- > pId :*: pName :*: pAge :*: pPet = selectors people
 --
---   This example will create a table with the column types
---   @Int :*: Text :*: Int :*: Maybe Text@, where the first field is
---   an auto-incrementing primary key.
+--   This will result in a table of @Person@s, with an auto-incrementing primary
+--   key.
 --
---   If the given type is not a record type, the column names will be
+--   If the given type does not have record selectors, the column names will be
 --   @col_1@, @col_2@, etc.
 table :: forall a. Relational a
          => TableName
@@ -112,14 +112,12 @@
 -- | A pair of the table with the given name and columns, and all its selectors.
 --   For example:
 --
--- > tbl :: Table (Int :*: Text)
+-- > tbl :: Table (Int, Text)
 -- > (tbl, tblBar :*: tblBaz)
--- >   =  tableWithSelectors "foo"
--- >   $  required "bar"
--- >   :*: required "baz"
+-- >   =  tableWithSelectors "foo" []
 -- >
 -- > q :: Query s Text
--- > q = tblBaz <$> select tbl
+-- > q = tblBaz `from` select tbl
 tableWithSelectors :: forall a. Relational a
                    => TableName
                    -> [Attr a]
@@ -133,12 +131,14 @@
 --   Selectors can be used to access the fields of a query result tuple, avoiding
 --   the need to pattern match on the entire tuple.
 --
--- > tbl :: Table (Int :*: Text)
--- > tbl = table "foo" $ required "bar" :*: required "baz"
+-- > tbl :: Table (Int, Text)
+-- > tbl = table "foo" []
 -- > (tblBar :*: tblBaz) = selectors tbl
 -- >
 -- > q :: Query s Text
--- > q = tblBaz <$> select tbl
+-- > q = do
+-- >   row <- select tbl
+-- >   return (row ! tblBaz)
 selectors :: forall a. Relational a => Table a -> Selectors a
 selectors _ = selectorsFor (Proxy :: Proxy a)
 
diff --git a/src/Database/Selda/Unsafe.hs b/src/Database/Selda/Unsafe.hs
--- a/src/Database/Selda/Unsafe.hs
+++ b/src/Database/Selda/Unsafe.hs
@@ -23,7 +23,7 @@
 -- | Cast an aggregate to another type, using whichever coercion semantics
 --   are used by the underlying SQL implementation.
 castAggr :: forall s a b. SqlType b => Aggr s a -> Aggr s b
-castAggr = liftAggr $ Cast (sqlType (Proxy :: Proxy b))
+castAggr = liftAggr cast
 
 -- | A unary operation. Note that the provided function name is spliced
 --   directly into the resulting SQL query. Thus, this function should ONLY
