diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# hpqtypes-extras-1.10.2.0 (2020-01-20)
+* Add support for UNION clause
+* Add support for GHC 8.8
+
 # hpqtypes-extras-1.10.1.0 (2020-01-09)
 * Add support for ON CONFLICT clause
 
diff --git a/hpqtypes-extras.cabal b/hpqtypes-extras.cabal
--- a/hpqtypes-extras.cabal
+++ b/hpqtypes-extras.cabal
@@ -1,6 +1,6 @@
 cabal-version:       1.18
 name:                hpqtypes-extras
-version:             1.10.1.0
+version:             1.10.2.0
 synopsis:            Extra utilities for hpqtypes library
 description:         The following extras for hpqtypes library:
                      .
@@ -20,7 +20,7 @@
 copyright:           Scrive AB
 category:            Database
 build-type:          Simple
-tested-with:         GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.4, GHC == 8.6.5
+tested-with:         GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.2
 
 Source-repository head
   Type:     git
@@ -50,7 +50,7 @@
   other-modules:   Database.PostgreSQL.PQTypes.Checks.Util
                  , Database.PostgreSQL.PQTypes.Utils.NubList
 
-  build-depends: base              >= 4.9     && < 4.13
+  build-depends: base              >= 4.9     && < 4.14
                , hpqtypes          >= 1.8.0.0 && < 1.9.0.0
                , base16-bytestring >= 0.1     && < 0.2
                , bytestring        >= 0.10    && < 0.11
diff --git a/src/Database/PostgreSQL/PQTypes/Model/Migration.hs b/src/Database/PostgreSQL/PQTypes/Model/Migration.hs
--- a/src/Database/PostgreSQL/PQTypes/Model/Migration.hs
+++ b/src/Database/PostgreSQL/PQTypes/Model/Migration.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {- |
 
 Using migrations is fairly easy. After you've defined the lists of
@@ -48,8 +49,13 @@
 
   -- | Migration for creating an index concurrently.
   | CreateIndexConcurrentlyMigration
+#if __GLASGOW_HASKELL__ >= 806
       (RawSQL ()) -- ^ Table name
       TableIndex  -- ^ Index
+#else
+      (RawSQL ())
+      TableIndex
+#endif
 
 -- | Migration object.
 data Migration m =
diff --git a/src/Database/PostgreSQL/PQTypes/SQL/Builder.hs b/src/Database/PostgreSQL/PQTypes/SQL/Builder.hs
--- a/src/Database/PostgreSQL/PQTypes/SQL/Builder.hs
+++ b/src/Database/PostgreSQL/PQTypes/SQL/Builder.hs
@@ -180,6 +180,7 @@
   , sqlLimit
   , sqlDistinct
   , sqlWith
+  , sqlUnion
 
   , SqlTurnIntoSelect
   , sqlTurnIntoSelect
@@ -321,6 +322,7 @@
 
 data SqlSelect = SqlSelect
   { sqlSelectFrom     :: SQL
+  , sqlSelectUnion    :: [SQL]
   , sqlSelectDistinct :: Bool
   , sqlSelectResult   :: [SQL]
   , sqlSelectWhere    :: [SqlCondition]
@@ -426,21 +428,24 @@
   withSQL = withSQL . toSQLCommand
 
 instance Sqlable SqlSelect where
-  toSQLCommand cmd =
-        emitClausesSepComma "WITH" (map (\(name,command) -> name <+> "AS" <+> parenthesize command) (sqlSelectWith cmd)) <+>
-        "SELECT" <+> (if sqlSelectDistinct cmd then "DISTINCT" else mempty) <+>
-        sqlConcatComma (sqlSelectResult cmd) <+>
-        emitClause "FROM" (sqlSelectFrom cmd) <+>
-        emitClausesSep "WHERE" "AND" (map toSQLCommand $ sqlSelectWhere cmd) <+>
-        emitClausesSepComma "GROUP BY" (sqlSelectGroupBy cmd) <+>
-        emitClausesSep "HAVING" "AND" (sqlSelectHaving cmd) <+>
-        emitClausesSepComma "ORDER BY" (sqlSelectOrderBy cmd) <+>
-        (if sqlSelectOffset cmd > 0
-           then unsafeSQL ("OFFSET " ++ show (sqlSelectOffset cmd))
-           else "") <+>
-        (if sqlSelectLimit cmd >= 0
-           then unsafeSQL ("LIMIT " ++ show (sqlSelectLimit cmd))
-           else "")
+  toSQLCommand cmd = smconcat
+    [ emitClausesSepComma "WITH" $
+      map (\(name,command) -> name <+> "AS" <+> parenthesize command) (sqlSelectWith cmd)
+    , "SELECT" <+> (if sqlSelectDistinct cmd then "DISTINCT" else mempty)
+    , sqlConcatComma (sqlSelectResult cmd)
+    , emitClause "FROM" (sqlSelectFrom cmd)
+    , emitClausesSep "WHERE" "AND" (map toSQLCommand $ sqlSelectWhere cmd)
+    , emitClausesSep "UNION" "UNION" (sqlSelectUnion cmd)
+    , emitClausesSepComma "GROUP BY" (sqlSelectGroupBy cmd)
+    , emitClausesSep "HAVING" "AND" (sqlSelectHaving cmd)
+    , emitClausesSepComma "ORDER BY" (sqlSelectOrderBy cmd)
+    , if sqlSelectOffset cmd > 0
+      then unsafeSQL ("OFFSET " ++ show (sqlSelectOffset cmd))
+      else ""
+    , if sqlSelectLimit cmd >= 0
+      then unsafeSQL ("LIMIT " ++ show (sqlSelectLimit cmd))
+      else ""
+    ]
 
 instance Sqlable SqlInsert where
   toSQLCommand cmd =
@@ -468,6 +473,7 @@
     "INSERT INTO" <+> sqlInsertSelectWhat cmd <+>
     parenthesize (sqlConcatComma (map fst (sqlInsertSelectSet cmd))) <+>
     parenthesize (toSQLCommand (SqlSelect { sqlSelectFrom    = sqlInsertSelectFrom cmd
+                                          , sqlSelectUnion   = []
                                           , sqlSelectDistinct = sqlInsertSelectDistinct cmd
                                           , sqlSelectResult  = fmap snd $ sqlInsertSelectSet cmd
                                           , sqlSelectWhere   = sqlInsertSelectWhere cmd
@@ -505,11 +511,11 @@
 
 sqlSelect :: SQL -> State SqlSelect () -> SqlSelect
 sqlSelect table refine =
-  execState refine (SqlSelect table False [] [] [] [] [] 0 (-1) [])
+  execState refine (SqlSelect table [] False [] [] [] [] [] 0 (-1) [])
 
 sqlSelect2 :: SQL -> State SqlSelect () -> SqlSelect
 sqlSelect2 from refine =
-  execState refine (SqlSelect from False [] [] [] [] [] 0 (-1) [])
+  execState refine (SqlSelect from [] False [] [] [] [] [] 0 (-1) [])
 
 sqlInsert :: SQL -> State SqlInsert () -> SqlInsert
 sqlInsert table refine =
@@ -564,7 +570,10 @@
 sqlWith :: (MonadState v m, SqlWith v, Sqlable s) => SQL -> s -> m ()
 sqlWith name sql = modify (\cmd -> sqlWith1 cmd name (toSQLCommand sql))
 
-
+-- | Note: WHERE clause of the main SELECT is treated specially, i.e. it only
+-- applies to the main SELECT, not the whole union.
+sqlUnion :: (MonadState SqlSelect m, Sqlable sql) => [sql] -> m ()
+sqlUnion sqls = modify (\cmd -> cmd { sqlSelectUnion = map toSQLCommand sqls })
 
 class SqlWhere a where
   sqlWhere1 :: a -> SqlCondition -> a
@@ -1046,6 +1055,7 @@
                                              if isSqlEmpty (sqlUpdateFrom s)
                                              then ""
                                              else "," <+> sqlUpdateFrom s
+                        , sqlSelectUnion    = []
                         , sqlSelectDistinct = False
                         , sqlSelectResult  = if null (sqlUpdateResult s)
                                              then ["TRUE"]
@@ -1065,6 +1075,7 @@
                                              if isSqlEmpty (sqlDeleteUsing s)
                                              then ""
                                              else "," <+> sqlDeleteUsing s
+                        , sqlSelectUnion    = []
                         , sqlSelectDistinct = False
                         , sqlSelectResult  = if null (sqlDeleteResult s)
                                              then ["TRUE"]
@@ -1081,6 +1092,7 @@
 instance SqlTurnIntoSelect SqlInsertSelect where
   sqlTurnIntoSelect s = SqlSelect
                         { sqlSelectFrom    = sqlInsertSelectFrom s
+                        , sqlSelectUnion   = []
                         , sqlSelectDistinct = False
                         , sqlSelectResult  = sqlInsertSelectResult s
                         , sqlSelectWhere   = sqlInsertSelectWhere s
