diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 0.7.6.0
+
+* Added `matchMaybe`
+
+* Added `SqlVarcharN` and supporting functions
+
 ## 0.7.5.0
 
 * Added `enumMapperWithSchema`.  Thanks to Steve Mao.
diff --git a/opaleye.cabal b/opaleye.cabal
--- a/opaleye.cabal
+++ b/opaleye.cabal
@@ -1,6 +1,6 @@
 name:            opaleye
 copyright:       Copyright (c) 2014-2018 Purely Agile Limited; 2019-2021 Tom Ellis
-version:         0.7.5.0
+version:         0.7.6.0
 synopsis:        An SQL-generating DSL targeting PostgreSQL
 description:     An SQL-generating DSL targeting PostgreSQL.  Allows
                  Postgres queries to be written within Haskell in a
diff --git a/src/Opaleye/Internal/Constant.hs b/src/Opaleye/Internal/Constant.hs
--- a/src/Opaleye/Internal/Constant.hs
+++ b/src/Opaleye/Internal/Constant.hs
@@ -68,6 +68,15 @@
 instance D.Default ToFields LT.Text (Column T.SqlText) where
   def = toToFields T.sqlLazyText
 
+instance D.Default ToFields String (Column T.SqlVarcharN) where
+  def = toToFields T.sqlStringVarcharN
+
+instance D.Default ToFields ST.Text (Column T.SqlVarcharN) where
+  def = toToFields T.sqlStrictTextVarcharN
+
+instance D.Default ToFields LT.Text (Column T.SqlVarcharN) where
+  def = toToFields T.sqlLazyTextVarcharN
+
 instance D.Default ToFields Sci.Scientific (Column T.SqlNumeric) where
   def = toToFields T.sqlNumeric
 
diff --git a/src/Opaleye/Internal/Inferrable.hs b/src/Opaleye/Internal/Inferrable.hs
--- a/src/Opaleye/Internal/Inferrable.hs
+++ b/src/Opaleye/Internal/Inferrable.hs
@@ -56,6 +56,9 @@
 instance text ~ ST.Text => D.Default (Inferrable FromField) T.SqlText text where
   def = Inferrable D.def
 
+instance varchar ~ ST.Text => D.Default (Inferrable FromField) T.SqlVarcharN varchar where
+  def = Inferrable D.def
+
 instance (Typeable h, D.Default (Inferrable FromField) f h, hs ~ [h])
   => D.Default (Inferrable FromField) (T.SqlArray f) hs where
   def = Inferrable (RQ.fromFieldArray (runInferrable D.def))
diff --git a/src/Opaleye/Internal/Join.hs b/src/Opaleye/Internal/Join.hs
--- a/src/Opaleye/Internal/Join.hs
+++ b/src/Opaleye/Internal/Join.hs
@@ -13,6 +13,7 @@
 import qualified Opaleye.Internal.Operators as Op
 import qualified Opaleye.Internal.PrimQuery as PQ
 import qualified Opaleye.Internal.PGTypesExternal as T
+import qualified Opaleye.Internal.Rebind as Rebind
 import qualified Opaleye.SqlTypes as T
 import qualified Opaleye.Column as C
 import           Opaleye.Field   (Field)
@@ -72,28 +73,16 @@
                   -> Q.Query a
                   -> Q.QueryArr (a -> Column T.PGBool) nullableA
 leftJoinAExplicit uA nullmaker rq =
-  Q.QueryArr $ \(p, t1) ->
-    let (columnsR, primQueryR, t2) = Q.runSimpleQueryArr rq ((), t1)
-        (newColumnsR, ljPEsR) = PM.run $ U.runUnpackspec uA (extractLeftJoinFields 2 t2) columnsR
+  Q.leftJoinQueryArr $ \(p, t1) ->
+    let (newColumnsR, right, tag') = flip Q.runSimpleQueryArr ((), t1) $ proc () -> do
+          a <- rq -< ()
+          Rebind.rebindExplicit uA -< a
         renamedNullable = toNullable nullmaker newColumnsR
         Column cond = p newColumnsR
     in ( renamedNullable
-       , \lat primQueryL -> PQ.Join
-           PQ.LeftJoin
-           cond
-           (PQ.NonLateral, primQueryL)
-           --- ^ I am reasonably confident that we don't need to rebind any
-           --- column names here.  Columns that can become NULL need
-           --- to be written here so that we can wrap them.  If we
-           --- don't constant columns can avoid becoming NULL.
-           --- However, these are the left columns and cannot become
-           --- NULL in a left join, so we are fine.
-           ---
-           --- Report about the "avoiding NULL" bug:
-           ---
-           ---     https://github.com/tomjaguarpaw/haskell-opaleye/issues/223
-           (lat, (PQ.Rebind True ljPEsR primQueryR))
-       , T.next t2)
+       , cond
+       , right
+       , tag')
 
 optionalRestrict :: D.Default U.Unpackspec a a
                  => S.Select a
diff --git a/src/Opaleye/Internal/MaybeFields.hs b/src/Opaleye/Internal/MaybeFields.hs
--- a/src/Opaleye/Internal/MaybeFields.hs
+++ b/src/Opaleye/Internal/MaybeFields.hs
@@ -16,15 +16,12 @@
 import qualified Opaleye.Internal.Binary as B
 import qualified Opaleye.Internal.Column as IC
 import qualified Opaleye.ToFields as Constant
-import qualified Opaleye.Internal.PackMap as PM
 import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ
 import           Opaleye.Internal.Inferrable (Inferrable(Inferrable),
                                               runInferrable)
-import qualified Opaleye.Internal.PrimQuery as PQ
 import qualified Opaleye.Internal.QueryArr as IQ
 import qualified Opaleye.Internal.Rebind as Rebind
 import qualified Opaleye.Internal.RunQuery as RQ
-import qualified Opaleye.Internal.Tag as Tag
 import qualified Opaleye.Internal.Unpackspec as U
 import qualified Opaleye.Internal.Values as V
 import           Opaleye.Select (Select, SelectArr)
@@ -35,7 +32,7 @@
                                              ifExplict, IfPP, EqPP(EqPP))
 import qualified Opaleye.Internal.Lateral
 import qualified Opaleye.SqlTypes
-import           Opaleye.SqlTypes (SqlBool, IsSqlType)
+import           Opaleye.SqlTypes (SqlBool, IsSqlType, SqlInt4)
 
 import           Control.Monad (replicateM_)
 
@@ -92,6 +89,18 @@
 maybeFields :: PP.Default IfPP b b => b -> (a -> b) -> MaybeFields a -> b
 maybeFields = maybeFieldsExplicit PP.def
 
+-- | Use a Haskell @\\case@ expression to pattern match on a
+-- 'MaybeFields'.
+--
+-- @
+-- example :: MaybeFields (Field SqlInt4) -> Field SqlInt4
+-- example mf = matchMaybe mf $ \\case
+--   Nothing -> 0
+--   Just x  -> x * 100
+-- @
+matchMaybe :: PP.Default IfPP b b => MaybeFields a -> (Maybe a -> b) -> b
+matchMaybe mf f = maybeFields (f Nothing) (f . Just) mf
+
 -- | The Opaleye analogue of 'Data.Maybe.fromMaybe'
 fromMaybeFields :: PP.Default IfPP b b => b -> MaybeFields b -> b
 fromMaybeFields = fromMaybeFieldsExplicit PP.def
@@ -129,19 +138,15 @@
   where isNotNull = Opaleye.Internal.Operators.not . Opaleye.Field.isNull
 
 optionalInternal :: (Field (Opaleye.Column.Nullable SqlBool) -> a -> r) -> Select a -> Select r
-optionalInternal f = IQ.QueryArr . go
-  where
+optionalInternal f query = IQ.leftJoinQueryArr $ \arg ->
     -- This is basically a left join on TRUE, but Shane (@duairc)
     -- wrote it to ensure that we don't need an Unpackspec a a.
-    go query arg = (r, join, Tag.next tag')
-      where
-        (r, right, tag') = flip IQ.runSimpleQueryArr arg $ proc () -> do
+    let (r, right, tag') = flip IQ.runSimpleQueryArr arg $ proc () -> do
           a <- query -< ()
           true_ <- Rebind.rebind -< Opaleye.Column.toNullable (IC.Column true)
           returnA -< f true_ a
-
-        join lat left = PQ.Join PQ.LeftJoin true (PQ.NonLateral, left) (lat, right)
-    true = HPQ.ConstExpr (HPQ.BoolLit True)
+        true = HPQ.ConstExpr (HPQ.BoolLit True)
+    in (r, true, right, tag')
 
 
 -- | An example to demonstrate how the functionality of (lateral)
diff --git a/src/Opaleye/Internal/PGTypesExternal.hs b/src/Opaleye/Internal/PGTypesExternal.hs
--- a/src/Opaleye/Internal/PGTypesExternal.hs
+++ b/src/Opaleye/Internal/PGTypesExternal.hs
@@ -51,6 +51,9 @@
 instance C.SqlString SqlText where
   sqlFromString = pgString
 
+instance C.SqlString SqlVarcharN where
+  sqlFromString = sqlStringVarcharN
+
 instance C.SqlString SqlCitext where
   sqlFromString = pgCiLazyText . CI.mk . LText.pack
 
@@ -71,6 +74,15 @@
 pgLazyText :: LText.Text -> Column PGText
 pgLazyText = IPT.literalColumn . HPQ.StringLit . LText.unpack
 
+sqlStringVarcharN :: String -> Column SqlVarcharN
+sqlStringVarcharN = IPT.literalColumn . HPQ.StringLit
+
+sqlStrictTextVarcharN :: SText.Text -> Column SqlVarcharN
+sqlStrictTextVarcharN = IPT.literalColumn . HPQ.StringLit . SText.unpack
+
+sqlLazyTextVarcharN :: LText.Text -> Column SqlVarcharN
+sqlLazyTextVarcharN = IPT.literalColumn . HPQ.StringLit . LText.unpack
+
 pgNumeric :: Sci.Scientific -> Column PGNumeric
 pgNumeric = IPT.literalColumn . HPQ.NumericLit
 
@@ -190,6 +202,8 @@
   showSqlType _ = "numeric"
 instance IsSqlType SqlText where
   showSqlType _ = "text"
+instance IsSqlType SqlVarcharN where
+  showSqlType _ = "varchar"
 instance IsSqlType SqlTime where
   showSqlType _ = "time"
 instance IsSqlType SqlTimestamp where
@@ -249,6 +263,9 @@
 data SqlInterval
 data SqlNumeric
 data SqlText
+-- | @VARCHAR(n)@ for any @n@.  Opaleye does not do anything to check
+-- that the @n@ you choose is correctly adhered to!
+data SqlVarcharN
 data SqlTime
 data SqlTimestamp
 -- | Be careful if you use Haskell's `Time.ZonedTime` with
diff --git a/src/Opaleye/Internal/QueryArr.hs b/src/Opaleye/Internal/QueryArr.hs
--- a/src/Opaleye/Internal/QueryArr.hs
+++ b/src/Opaleye/Internal/QueryArr.hs
@@ -58,6 +58,12 @@
   where g (a0, t0) = (a1, \lat primQuery -> PQ.times lat primQuery primQuery', t1)
           where (a1, primQuery', t1) = f (a0, t0)
 
+leftJoinQueryArr :: ((a, Tag) -> (b, HPQ.PrimExpr, PQ.PrimQuery, Tag)) -> QueryArr a b
+leftJoinQueryArr f = QueryArr g
+  where g (a0, t0) = (a1, \lat primQueryL ->
+                            PQ.Join PQ.LeftJoin cond (PQ.NonLateral, primQueryL) (lat, primQuery'), t1)
+          where (a1, cond, primQuery', t1) = f (a0, t0)
+
 {-# DEPRECATED simpleQueryArr "Use 'productQueryArr' instead. Its name indicates better what it actually does" #-}
 simpleQueryArr :: ((a, Tag) -> (b, PQ.PrimQuery, Tag)) -> QueryArr a b
 simpleQueryArr = productQueryArr
diff --git a/src/Opaleye/Internal/Rebind.hs b/src/Opaleye/Internal/Rebind.hs
--- a/src/Opaleye/Internal/Rebind.hs
+++ b/src/Opaleye/Internal/Rebind.hs
@@ -10,6 +10,9 @@
 import qualified Opaleye.Internal.Tag as Tag
 
 rebind :: Default Unpackspec a a => SelectArr a a
-rebind = QueryArr (\(a, tag) ->
-                     let (b, bindings) = PM.run (runUnpackspec def (PM.extractAttr "rebind" tag) a)
+rebind = rebindExplicit def
+
+rebindExplicit :: Unpackspec a b -> SelectArr a b
+rebindExplicit u = QueryArr (\(a, tag) ->
+                     let (b, bindings) = PM.run (runUnpackspec u (PM.extractAttr "rebind" tag) a)
                      in (b, \_ -> PQ.Rebind True bindings, Tag.next tag))
diff --git a/src/Opaleye/Internal/RunQuery.hs b/src/Opaleye/Internal/RunQuery.hs
--- a/src/Opaleye/Internal/RunQuery.hs
+++ b/src/Opaleye/Internal/RunQuery.hs
@@ -232,6 +232,15 @@
 instance DefaultFromField T.SqlText LT.Text where
   defaultFromField = fromPGSFromField
 
+instance DefaultFromField T.SqlVarcharN String where
+  defaultFromField = fromPGSFromField
+
+instance DefaultFromField T.SqlVarcharN ST.Text where
+  defaultFromField = fromPGSFromField
+
+instance DefaultFromField T.SqlVarcharN LT.Text where
+  defaultFromField = fromPGSFromField
+
 instance DefaultFromField T.SqlDate Time.Day where
   defaultFromField = fromPGSFromField
 
diff --git a/src/Opaleye/MaybeFields.hs b/src/Opaleye/MaybeFields.hs
--- a/src/Opaleye/MaybeFields.hs
+++ b/src/Opaleye/MaybeFields.hs
@@ -10,6 +10,7 @@
   MaybeFields,
   nothingFields,
   justFields,
+  matchMaybe,
   fromMaybeFields,
   maybeFields,
   maybeFieldsToSelect,
diff --git a/src/Opaleye/Order.hs b/src/Opaleye/Order.hs
--- a/src/Opaleye/Order.hs
+++ b/src/Opaleye/Order.hs
@@ -166,6 +166,7 @@
 instance SqlOrd T.SqlInt2
 instance SqlOrd T.SqlNumeric
 instance SqlOrd T.SqlText
+instance SqlOrd T.SqlVarcharN
 instance SqlOrd T.SqlTime
 instance SqlOrd T.SqlTimestamptz
 instance SqlOrd T.SqlTimestamp
diff --git a/src/Opaleye/SqlTypes.hs b/src/Opaleye/SqlTypes.hs
--- a/src/Opaleye/SqlTypes.hs
+++ b/src/Opaleye/SqlTypes.hs
@@ -51,10 +51,14 @@
   sqlString,
   sqlStrictText,
   sqlLazyText,
+  P.sqlStringVarcharN,
+  P.sqlStrictTextVarcharN,
+  P.sqlLazyTextVarcharN,
   sqlCiStrictText,
   sqlCiLazyText,
   -- ** Types
   SqlText,
+  SqlVarcharN,
   SqlCitext,
   -- * Array
   -- ** Creating values
@@ -95,6 +99,7 @@
                                                    SqlInt2,
                                                    SqlNumeric,
                                                    SqlText,
+                                                   SqlVarcharN,
                                                    SqlTime,
                                                    SqlTimestamp,
                                                    SqlTimestamptz,
