diff --git a/Database/Persist/EntityDef.hs b/Database/Persist/EntityDef.hs
--- a/Database/Persist/EntityDef.hs
+++ b/Database/Persist/EntityDef.hs
@@ -56,6 +56,7 @@
     { uniqueHaskell :: HaskellName
     , uniqueDBName  :: DBName
     , uniqueFields  :: [(HaskellName, DBName)]
+    , uniqueAttrs   :: [Attr]
     }
     deriving (Show, Eq, Read, Ord)
 
diff --git a/Database/Persist/GenericSql.hs b/Database/Persist/GenericSql.hs
--- a/Database/Persist/GenericSql.hs
+++ b/Database/Persist/GenericSql.hs
@@ -19,6 +19,9 @@
     , runSqlPool
     , Key
 
+    -- * Useful data types
+    , Checkmark(..)
+
     -- * Raw SQL queries
     -- $rawSql
     , rawSql
@@ -268,6 +271,76 @@
 
 show :: Show a => a -> Text
 show = pack . P.show
+
+
+-- | A 'Checkmark' should be used as a field type whenever a
+-- uniqueness constraint should guarantee that a certain kind of
+-- record may appear at most once, but other kinds of records may
+-- appear any number of times.
+--
+-- /NOTE:/ You need to mark any @Checkmark@ fields as @nullable@
+-- (see the following example).
+--
+-- For example, suppose there's a @Location@ entity that
+-- represents where a user has lived:
+--
+-- @
+-- Location
+--     user    UserId
+--     name    Text
+--     current Checkmark nullable
+--
+--     UniqueLocation user current
+-- @
+--
+-- The @UniqueLocation@ constraint allows any number of
+-- 'Inactive' @Location@s to be @current@.  However, there may be
+-- at most one @current@ @Location@ per user (i.e., either zero
+-- or one per user).
+--
+-- This data type works because of the way that SQL treats
+-- @NULL@able fields within uniqueness constraints.  The SQL
+-- standard says that @NULL@ values should be considered
+-- different, so we represent 'Inactive' as SQL @NULL@, thus
+-- allowing any number of 'Inactive' records.  On the other hand,
+-- we represent 'Active' as @TRUE@, so the uniqueness constraint
+-- will disallow more than one 'Active' record.
+--
+-- /Note:/ There may be DBMSs that do not respect the SQL
+-- standard's treatment of @NULL@ values on uniqueness
+-- constraints, please check if this data type works before
+-- relying on it.
+--
+-- The SQL @BOOLEAN@ type is used because it's the smallest data
+-- type available.  Note that we never use @FALSE@, just @TRUE@
+-- and @NULL@.  Provides the same behavior @Maybe ()@ would if
+-- @()@ was a valid 'PersistField'.
+data Checkmark = Active
+                 -- ^ When used on a uniqueness constraint, there
+                 -- may be at most one 'Active' record.
+               | Inactive
+                 -- ^ When used on a uniqueness constraint, there
+                 -- may be any number of 'Inactive' records.
+    deriving (Eq, Ord, Read, Show, Enum, Bounded)
+
+instance PersistField Checkmark where
+    toPersistValue Active   = PersistBool True
+    toPersistValue Inactive = PersistNull
+    fromPersistValue PersistNull         = Right Inactive
+    fromPersistValue (PersistBool True)  = Right Active
+    fromPersistValue (PersistBool False) =
+      Left "PersistField Checkmark: found unexpected FALSE value"
+    fromPersistValue other =
+      Left $ "PersistField Checkmark: unknown value " ++ show other
+    sqlType    _ = SqlBool
+    isNullable _ = True
+
+instance PathPiece Checkmark where
+    toPathPiece = show
+    fromPathPiece txt =
+      case reads (T.unpack txt) of
+        [(a, "")] -> Just a
+        _         -> Nothing
 
 
 -- $rawSql
diff --git a/Database/Persist/GenericSql/Internal.hs b/Database/Persist/GenericSql/Internal.hs
--- a/Database/Persist/GenericSql/Internal.hs
+++ b/Database/Persist/GenericSql/Internal.hs
@@ -26,7 +26,7 @@
 import Database.Persist.Store
 import Control.Exception.Lifted (bracket)
 import Control.Monad.Trans.Control (MonadBaseControl)
-import Database.Persist.Util (nullable)
+import Database.Persist.Util (nullable, IsNullable(NotNullable))
 import Data.Text (Text)
 import qualified Data.Text as T
 import Data.Monoid (Monoid, mappend, mconcat)
@@ -115,7 +115,7 @@
     go fd p =
         Column
             (fieldDB fd)
-            (nullable (fieldAttrs fd) || entitySum t)
+            (nullable (fieldAttrs fd) /= NotNullable || entitySum t)
             (maybe (sqlType p) SqlOther $ listToMaybe $ mapMaybe (T.stripPrefix "sqltype=") $ fieldAttrs fd)
             (def $ fieldAttrs fd)
             (maxLen $ fieldAttrs fd)
diff --git a/Database/Persist/Quasi.hs b/Database/Persist/Quasi.hs
--- a/Database/Persist/Quasi.hs
+++ b/Database/Persist/Quasi.hs
@@ -248,8 +248,10 @@
         = Just $ UniqueDef
             (HaskellName n)
             (DBName $ psToDBName ps n)
-            (map (HaskellName &&& getDBName defs) rest)
+            (map (HaskellName &&& getDBName defs) fields)
+            attrs
   where
+    (fields,attrs) = break ("!" `T.isPrefixOf`) rest
     getDBName [] t = error $ "Unknown column in unique constraint: " ++ show t
     getDBName (d:ds) t
         | fieldHaskell d == HaskellName t = fieldDB d
diff --git a/Database/Persist/Util.hs b/Database/Persist/Util.hs
--- a/Database/Persist/Util.hs
+++ b/Database/Persist/Util.hs
@@ -1,17 +1,35 @@
 {-# LANGUAGE OverloadedStrings #-}
 module Database.Persist.Util
     ( nullable
+    , IsNullable(..)
+    , WhyNullable(..)
     , deprecate
     ) where
 
 import System.IO.Unsafe (unsafePerformIO)
 import Data.Text
 
-nullable :: [Text] -> Bool
+nullable :: [Text] -> IsNullable
 nullable s
-    | "Maybe" `elem` s = True
-    | "null" `elem` s = deprecate "Please replace null with Maybe" True
-    | otherwise = False
+    | "Maybe"    `elem` s = Nullable ByMaybeAttr
+    | "nullable" `elem` s = Nullable ByNullableAttr
+    | "null"     `elem` s = deprecate "Please replace null with Maybe" (Nullable ByMaybeAttr)
+    | otherwise = NotNullable
+
+
+data IsNullable = Nullable !WhyNullable
+                | NotNullable
+                  deriving (Eq, Show)
+
+-- | The reason why a field is 'nullable' is very important.  A
+-- field that is nullable because of a @Maybe@ tag will have its
+-- type changed from @A@ to @Maybe A@.  OTOH, a field that is
+-- nullable because of a @nullable@ tag will remain with the same
+-- type.
+data WhyNullable = ByMaybeAttr
+                 | ByNullableAttr
+                  deriving (Eq, Show)
+
 
 deprecate :: String -> a -> a
 deprecate s x = unsafePerformIO $ do
diff --git a/persistent.cabal b/persistent.cabal
--- a/persistent.cabal
+++ b/persistent.cabal
@@ -1,5 +1,5 @@
 name:            persistent
-version:         1.1.0.1
+version:         1.1.2
 license:         MIT
 license-file:    LICENSE
 author:          Michael Snoyman <michael@snoyman.com>
