diff --git a/esqueleto.cabal b/esqueleto.cabal
--- a/esqueleto.cabal
+++ b/esqueleto.cabal
@@ -1,5 +1,5 @@
 name:                esqueleto
-version:             2.2.8
+version:             2.2.9
 synopsis:            Type-safe EDSL for SQL queries on persistent backends.
 homepage:            https://github.com/prowdsponsor/esqueleto
 license:             BSD3
diff --git a/src/Database/Esqueleto.hs b/src/Database/Esqueleto.hs
--- a/src/Database/Esqueleto.hs
+++ b/src/Database/Esqueleto.hs
@@ -45,9 +45,9 @@
              , (==.), (>=.), (>.), (<=.), (<.), (!=.), (&&.), (||.)
              , (+.), (-.), (/.), (*.)
              , random_, round_, ceiling_, floor_
-             , min_, max_, sum_, avg_, lower_
+             , min_, max_, sum_, avg_, castNum, castNumM
              , coalesce, coalesceDefault
-             , like, ilike, (%), concat_, (++.)
+             , lower_, like, ilike, (%), concat_, (++.)
              , subList_select, subList_selectDistinct, valList
              , in_, notIn, exists, notExists
              , set, (=.), (+=.), (-=.), (*=.), (/=.)
diff --git a/src/Database/Esqueleto/Internal/Language.hs b/src/Database/Esqueleto/Internal/Language.hs
--- a/src/Database/Esqueleto/Internal/Language.hs
+++ b/src/Database/Esqueleto/Internal/Language.hs
@@ -350,8 +350,30 @@
   min_     :: (PersistField a) => expr (Value a) -> expr (Value (Maybe a))
   max_     :: (PersistField a) => expr (Value a) -> expr (Value (Maybe a))
   avg_     :: (PersistField a, PersistField b) => expr (Value a) -> expr (Value (Maybe b))
-  lower_   :: (PersistField a, IsString a) => expr (Value a) -> expr (Value a)
 
+  -- | Allow a number of one type to be used as one of another
+  -- type via an implicit cast.  An explicit cast is not made,
+  -- this function changes only the types on the Haskell side.
+  --
+  -- /Caveat/: Trying to use @castNum@ from @Double@ to @Int@
+  -- will not result in an integer, the original fractional
+  -- number will still be used!  Use 'round_', 'ceiling_' or
+  -- 'floor_' instead.
+  --
+  -- /Safety/: This operation is mostly safe due to the 'Num'
+  -- constraint between the types and the fact that RDBMSs
+  -- usually allow numbers of different types to be used
+  -- interchangeably.  However, there may still be issues with
+  -- the query not being accepted by the RDBMS or @persistent@
+  -- not being able to parse it.
+  --
+  -- /Since: 2.2.9/
+  castNum :: (Num a, Num b) => expr (Value a) -> expr (Value b)
+  -- | Same as 'castNum', but for nullable values.
+  --
+  -- /Since: 2.2.9/
+  castNumM :: (Num a, Num b) => expr (Value (Maybe a)) -> expr (Value (Maybe b))
+
   -- | @COALESCE@ function. Evaluates the arguments in order and
   -- returns the value of the first non-NULL expression, or NULL
   -- (Nothing) otherwise. Some RDBMSs (such as SQLite) require
@@ -368,6 +390,8 @@
   -- /Since: 1.4.3/
   coalesceDefault :: PersistField a => [expr (Value (Maybe a))] -> expr (Value a) -> expr (Value a)
 
+  -- | @LOWER@ function.
+  lower_ :: (PersistField a, IsString a) => expr (Value a) -> expr (Value a)
   -- | @LIKE@ operator.
   like :: (PersistField s, IsString s) => expr (Value s) -> expr (Value s) -> expr (Value Bool)
   -- | @ILIKE@ operator (case-insensitive @LIKE@).
diff --git a/src/Database/Esqueleto/Internal/Sql.hs b/src/Database/Esqueleto/Internal/Sql.hs
--- a/src/Database/Esqueleto/Internal/Sql.hs
+++ b/src/Database/Esqueleto/Internal/Sql.hs
@@ -475,11 +475,14 @@
   min_     = unsafeSqlFunction "MIN"
   max_     = unsafeSqlFunction "MAX"
   avg_     = unsafeSqlFunction "AVG"
-  lower_   = unsafeSqlFunction "LOWER"
 
+  castNum  = veryUnsafeCoerceSqlExprValue
+  castNumM = veryUnsafeCoerceSqlExprValue
+
   coalesce              = unsafeSqlFunctionParens "COALESCE"
   coalesceDefault exprs = unsafeSqlFunctionParens "COALESCE" . (exprs ++) . return . just
 
+  lower_  = unsafeSqlFunction "LOWER"
   like    = unsafeSqlBinOp    " LIKE "
   ilike   = unsafeSqlBinOp    " ILIKE "
   (%)     = unsafeSqlValue    "'%'"
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -118,6 +118,9 @@
     name String
     Foreign Point fkpoint centerX centerY
     deriving Eq Show
+  Numbers
+    int    Int
+    double Double
 |]
 
 -- | this could be achieved with S.fromList, but not all lists
@@ -1205,8 +1208,8 @@
           ret <- select $ from (\(_::(SqlExpr (Entity BlogPost))) -> return countRows)
           liftIO $ ret `shouldBe` [Value (3::Int)]
 
-    describe "rand works" $ do
-      it "returns result in random order" $
+    describe "Math-related functions" $ do
+      it "rand returns result in random order" $
         run $ do
           replicateM_ 20 $ do
             _ <- insert p1
@@ -1225,6 +1228,17 @@
                     return (p ^. PersonId)
 
           liftIO $ (ret1 == ret2) `shouldBe` False
+
+      it "castNum works for multiplying Int and Double" $
+        run $ do
+          mapM_ insert [Numbers 2 3.4, Numbers 7 1.1]
+          ret <-
+            select $
+            from $ \n -> do
+            let r = castNum (n ^. NumbersInt) *. n ^. NumbersDouble
+            orderBy [asc r]
+            return r
+          liftIO $ ret `shouldBe` [Value 6.8, Value 7.7]
 
     describe "case" $ do
       it "Works for a simple value based when - False" $
