diff --git a/docs/en/jpql-with-kotlin-jdsl/expressions.md b/docs/en/jpql-with-kotlin-jdsl/expressions.md
index 7246176b5..15e3c1e2e 100644
--- a/docs/en/jpql-with-kotlin-jdsl/expressions.md
+++ b/docs/en/jpql-with-kotlin-jdsl/expressions.md
@@ -228,6 +228,7 @@ Use the following functions to build arithmetic functions:
 * EXP (exp)
 * FLOOR (floor)
 * ROUND (round)
+* SIGN (sign)
 * SQRT (sqrt)
 
 ```kotlin
@@ -241,6 +242,8 @@ floor(path(Book::price))
 
 round(path(Book::price), 2)
 
+sign(path(Book::price))
+
 sqrt(path(Book::price))
 ```
 
@@ -250,7 +253,6 @@ sqrt(path(Book::price))
 | LN       | not yet      |
 | MOD      | not yet      |
 | POWER    | not yet      |
-| SIGN     | not yet      |
 | SIZE     | not yet      |
 | INDEX    | not yet      |
 
diff --git a/docs/ko/jpql-with-kotlin-jdsl/expressions.md b/docs/ko/jpql-with-kotlin-jdsl/expressions.md
index 5313adc51..fa545e6e3 100644
--- a/docs/ko/jpql-with-kotlin-jdsl/expressions.md
+++ b/docs/ko/jpql-with-kotlin-jdsl/expressions.md
@@ -224,6 +224,7 @@ locate("Book", path(Book::title))
 * EXP (exp)
 * FLOOR (floor)
 * ROUND (round)
+* SIGN (sign)
 * SQRT (sqrt)
 
 ```kotlin
@@ -237,6 +238,8 @@ floor(path(Book::price))
 
 round(path(Book::price), 2)
 
+sign(path(Book::price))
+
 sqrt(path(Book::price))
 ```
 
@@ -246,7 +249,6 @@ sqrt(path(Book::price))
 | LN       | not yet      |
 | MOD      | not yet      |
 | POWER    | not yet      |
-| SIGN     | not yet      |
 | SIZE     | not yet      |
 | INDEX    | not yet      |
 
diff --git a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt
index 9e372a559..be3bcec73 100644
--- a/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt
+++ b/dsl/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/Jpql.kt
@@ -632,6 +632,30 @@ open class Jpql : JpqlDsl {
         return Expressions.round(value.toExpression(), scale.toExpression())
     }
 
+    /**
+     * Creates an expression that represents the sign of value.
+     *
+     * - If value is positive, it returns 1.
+     * - If value is negative, it returns -1.
+     * - If value is zero, it returns 0.
+     */
+    @SinceJdsl("3.4.0")
+    fun <T : Any, V : Number> sign(expr: KProperty1<T, @Exact V>): Expression<Int> {
+        return Expressions.sign(Paths.path(expr))
+    }
+
+    /**
+     * Creates an expression that represents the sign of value.
+     *
+     * - If value is positive, it returns 1.
+     * - If value is negative, it returns -1.
+     * - If value is zero, it returns 0.
+     */
+    @SinceJdsl("3.4.0")
+    fun <T : Number> sign(value: Expressionable<T>): Expression<Int> {
+        return Expressions.sign(value.toExpression())
+    }
+
     /**
      * Creates an expression that represents the square root of value.
      */
diff --git a/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/SignDslTest.kt b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/SignDslTest.kt
new file mode 100644
index 000000000..0e3ad933c
--- /dev/null
+++ b/dsl/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/dsl/jpql/expression/SignDslTest.kt
@@ -0,0 +1,47 @@
+package com.linecorp.kotlinjdsl.dsl.jpql.expression
+
+import com.linecorp.kotlinjdsl.dsl.jpql.entity.book.Book
+import com.linecorp.kotlinjdsl.dsl.jpql.queryPart
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import com.linecorp.kotlinjdsl.querymodel.jpql.path.Paths
+import org.assertj.core.api.WithAssertions
+import org.junit.jupiter.api.Test
+
+class SignDslTest : WithAssertions {
+    private val expression1 = Paths.path(Book::salePrice)
+
+    @Test
+    fun `sign() with a property`() {
+        // when
+        val expression = queryPart {
+            sign(Book::price)
+        }.toExpression()
+
+        val actual: Expression<Int> = expression // for type check
+
+        // then
+        val expected = Expressions.sign(
+            value = Paths.path(Book::price),
+        )
+
+        assertThat(actual).isEqualTo(expected)
+    }
+
+    @Test
+    fun `sign() with a expression`() {
+        // when
+        val expression = queryPart {
+            sign(expression1)
+        }.toExpression()
+
+        val actual: Expression<Int> = expression // for type check
+
+        // then
+        val expected = Expressions.sign(
+            value = expression1,
+        )
+
+        assertThat(actual).isEqualTo(expected)
+    }
+}
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt
index 991c6fcac..8cadac312 100644
--- a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/Expressions.kt
@@ -33,6 +33,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlParam
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPathType
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRound
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSign
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSqrt
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubquery
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubstring
@@ -252,6 +253,14 @@ object Expressions {
         return JpqlRound(value, scale)
     }
 
+    /**
+     * Creates an expression that represents the sign of a numeric value.
+     */
+    @SinceJdsl("3.4.0")
+    fun <T : Number> sign(value: Expression<T>): Expression<Int> {
+        return JpqlSign(value)
+    }
+
     /**
      * Creates an expression that represents the square root of the value.
      */
diff --git a/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlSign.kt b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlSign.kt
new file mode 100644
index 000000000..25160d693
--- /dev/null
+++ b/query-model/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/impl/JpqlSign.kt
@@ -0,0 +1,12 @@
+package com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
+
+/**
+ * Expression that calculates the sign of a numeric [value].
+ */
+@Internal
+data class JpqlSign<T : Number> internal constructor(
+    val value: Expression<T>,
+) : Expression<Int>
diff --git a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt
index 79e3a3ad6..3619c75ed 100644
--- a/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt
+++ b/query-model/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/querymodel/jpql/expression/ExpressionsTest.kt
@@ -35,6 +35,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlParam
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPathType
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlPlus
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlRound
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSign
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSqrt
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubquery
 import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSubstring
@@ -404,6 +405,19 @@ class ExpressionsTest : WithAssertions {
         assertThat(actual).isEqualTo(expected)
     }
 
+    @Test
+    fun sign() {
+        // when
+        val actual = Expressions.sign(intExpression1)
+
+        // then
+        val expected = JpqlSign(
+            intExpression1,
+        )
+
+        assertThat(actual).isEqualTo(expected)
+    }
+
     @Test
     fun sqrt() {
         // when
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt
index a64860996..3185ada84 100644
--- a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/JpqlRenderContext.kt
@@ -99,6 +99,7 @@ import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPlusSerializer
 import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlPredicateParenthesesSerializer
 import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlRoundSerializer
 import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSelectQuerySerializer
+import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSignSerializer
 import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSortSerializer
 import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSqrtSerializer
 import com.linecorp.kotlinjdsl.render.jpql.serializer.impl.JpqlSubquerySerializer
@@ -350,6 +351,7 @@ private class DefaultModule : JpqlRenderModule {
             JpqlPredicateParenthesesSerializer(),
             JpqlRoundSerializer(),
             JpqlSelectQuerySerializer(),
+            JpqlSignSerializer(),
             JpqlSortSerializer(),
             JpqlSqrtSerializer(),
             JpqlSubquerySerializer(),
diff --git a/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlSignSerializer.kt b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlSignSerializer.kt
new file mode 100644
index 000000000..bc88ba206
--- /dev/null
+++ b/render/jpql/src/main/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlSignSerializer.kt
@@ -0,0 +1,26 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.Internal
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSign
+import com.linecorp.kotlinjdsl.render.RenderContext
+import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer
+import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializer
+import com.linecorp.kotlinjdsl.render.jpql.writer.JpqlWriter
+import kotlin.reflect.KClass
+
+@Internal
+class JpqlSignSerializer : JpqlSerializer<JpqlSign<*>> {
+    override fun handledType(): KClass<JpqlSign<*>> {
+        return JpqlSign::class
+    }
+
+    override fun serialize(part: JpqlSign<*>, writer: JpqlWriter, context: RenderContext) {
+        val delegate = context.getValue(JpqlRenderSerializer)
+
+        writer.write("SIGN")
+
+        writer.writeParentheses {
+            delegate.serialize(part.value, writer, context)
+        }
+    }
+}
diff --git a/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlSignSerializerTest.kt b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlSignSerializerTest.kt
new file mode 100644
index 000000000..c8b56251c
--- /dev/null
+++ b/render/jpql/src/test/kotlin/com/linecorp/kotlinjdsl/render/jpql/serializer/impl/JpqlSignSerializerTest.kt
@@ -0,0 +1,55 @@
+package com.linecorp.kotlinjdsl.render.jpql.serializer.impl
+
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
+import com.linecorp.kotlinjdsl.querymodel.jpql.expression.impl.JpqlSign
+import com.linecorp.kotlinjdsl.querymodel.jpql.path.Paths
+import com.linecorp.kotlinjdsl.render.TestRenderContext
+import com.linecorp.kotlinjdsl.render.jpql.entity.book.Book
+import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlRenderSerializer
+import com.linecorp.kotlinjdsl.render.jpql.serializer.JpqlSerializerTest
+import com.linecorp.kotlinjdsl.render.jpql.writer.JpqlWriter
+import io.mockk.impl.annotations.MockK
+import io.mockk.verifySequence
+import org.assertj.core.api.WithAssertions
+import org.junit.jupiter.api.Test
+
+@JpqlSerializerTest
+class JpqlSignSerializerTest : WithAssertions {
+    private val sut = JpqlSignSerializer()
+
+    @MockK
+    private lateinit var writer: JpqlWriter
+
+    @MockK
+    private lateinit var serializer: JpqlRenderSerializer
+
+    private val expression1 = Paths.path(Book::price)
+
+    @Test
+    fun handledType() {
+        // when
+        val actual = sut.handledType()
+
+        // then
+        assertThat(actual).isEqualTo(JpqlSign::class)
+    }
+
+    @Test
+    fun serialize() {
+        // given
+        val part = Expressions.sign(
+            value = expression1,
+        )
+        val context = TestRenderContext(serializer)
+
+        // when
+        sut.serialize(part as JpqlSign<*>, writer, context)
+
+        // then
+        verifySequence {
+            writer.write("SIGN")
+            writer.writeParentheses(any())
+            serializer.serialize(expression1, writer, context)
+        }
+    }
+}