| |

SQL 53 🛢️ Data Type Conversion with CAST and CONVERT

A value has a type. The type determines what the value can do: a string can be concatenated, a number can be added, a date can be compared to another date. When a value needs to be used in a context where its type is not accepted, it must be converted. SQL provides two functions for this: CAST, which is the standard, and CONVERT, which is the SQL Server and MySQL variant. The conversion is not always lossless, and the way it fails depends on the type and the database.

This chapter covers type conversion in full. You will learn the CAST syntax, the CONVERT syntax, the implicit conversions that the database performs automatically, the explicit conversions that require the functions, the conversion failure modes, and the patterns that use conversion in real queries.

Key point: CAST(expression AS type) is the standard conversion function. CONVERT(type, expression) is the SQL Server form, and CONVERT(expression, type) is the MySQL form. Implicit conversion happens when the database automatically converts a value to the type the context requires. Explicit conversion is when the query uses CAST or CONVERT. The explicit form is preferred because it is predictable. A conversion that fails produces an error in most databases, or a NULL in some.


Why type conversion matters

The type mismatch problem. A column that stores a numeric ID as a string cannot be compared to an integer without a conversion. The comparison WHERE id = 42 fails or produces unexpected results if id is a VARCHAR. The CAST function makes the conversion explicit.

The display problem. A number that is displayed as 42 and a number that is displayed as 42.00 are the same value with different types. The CAST function converts a number to a string with a specified format, or a string to a number with a specified precision.

The portability problem. The CAST function is standard and supported by PostgreSQL, MySQL, SQL Server, and Oracle. The CONVERT function is not standard; its syntax differs between SQL Server and MySQL. Writing portable SQL means using CAST where possible.

The comparison problem. Comparing a date to a string produces different results depending on the conversion. WHERE date_col = '2026-01-08' works if the database converts the string to a date. WHERE date_col = 20260108 may or may not. The explicit conversion removes the ambiguity.

The failure problem. A conversion that cannot be performed produces an error. Converting the string 'abc' to an integer fails. Converting an integer to a string always succeeds. Converting a string to a date depends on the format. Knowing which conversions succeed and which fail is knowing when the query will work.


a. The CAST function

The CAST function converts an expression to a specified type.

SELECT CAST('42' AS integer);       -- 42
SELECT CAST(42 AS text);            -- '42'
SELECT CAST('2026-01-08' AS date);  -- 2026-01-08
SELECT CAST(42.7 AS integer);       -- 43 (rounds)
SELECT CAST(42.7 AS numeric(10,2)); -- 42.70

The syntax is CAST(expression AS type). The type is the target type. The expression is the value to convert.

The common conversions:

FromToResult
'42'integer42
'42.7'numeric42.7
42text'42'
42.7integer43
'2026-01-08'date2026-01-08
'2026-01-08 10:30'timestamp2026-01-08 10:30:00
'true'booleantrue
truetext'true'

The conversion from a string to a number succeeds only if the string is a valid number. CAST('42' AS integer) succeeds. CAST('abc' AS integer) fails with an error.

SELECT CAST('abc' AS integer);
-- ERROR: invalid input syntax for type integer: "abc"

The conversion from a number to a string always succeeds.

SELECT CAST(42 AS text);       -- '42'
SELECT CAST(42.7 AS text);     -- '42.7'
SELECT CAST(-42 AS text);      -- '-42'

The conversion from a number to an integer rounds. CAST(42.7 AS integer) is 43. The rounding is half away from zero for the numeric type.

SELECT CAST(42.4 AS integer);  -- 42
SELECT CAST(42.5 AS integer);  -- 43
SELECT CAST(42.6 AS integer);  -- 43
SELECT CAST(-42.5 AS integer); -- -43

The conversion from a string to a date depends on the format. The standard format is YYYY-MM-DD. A string in a different format may fail or be misinterpreted.

SELECT CAST('2026-01-08' AS date);   -- 2026-01-08
SELECT CAST('01/08/2026' AS date);   -- depends on locale

The CAST function is the standard. It is supported by PostgreSQL, MySQL, SQL Server, Oracle, and SQLite.

The :: operator is the PostgreSQL shorthand for CAST.

SELECT '42'::integer;       -- 42
SELECT 42::text;            -- '42'
SELECT '2026-01-08'::date;  -- 2026-01-08

The :: is more concise but is not standard. It is PostgreSQL-specific.


b. The CONVERT function

The CONVERT function is not standard. It has two forms, one in SQL Server and one in MySQL.

In SQL Server, the syntax is CONVERT(type, expression, style). The style is an optional integer that specifies the format for date and time conversions.

SELECT CONVERT(integer, '42');           -- 42
SELECT CONVERT(varchar, 42);             -- '42'
SELECT CONVERT(date, '2026-01-08');      -- 2026-01-08
SELECT CONVERT(varchar, GETDATE(), 23);  -- '2026-01-08' (ISO 8601)
SELECT CONVERT(varchar, GETDATE(), 101); -- '01/08/2026' (US)

The style codes are documented by Microsoft. The common ones:

StyleFormat
1mm/dd/yy
3dd/mm/yy
23yyyy-mm-dd
101mm/dd/yyyy
103dd/mm/yyyy
112yyyymmdd
120yyyy-mm-dd hh:mi:ss
126ISO 8601
127ISO 8601 with timezone

In MySQL, the syntax is CONVERT(expression, type) or CONVERT(expression USING charset). The type form converts between types, and the charset form converts between character sets.

SELECT CONVERT('42', SIGNED);           -- 42
SELECT CONVERT('42', UNSIGNED);         -- 42
SELECT CONVERT(42, CHAR);               -- '42'
SELECT CONVERT('2026-01-08', DATE);     -- 2026-01-08
SELECT CONVERT('abc' USING utf8mb4);    -- charset conversion

The MySQL types are SIGNED, UNSIGNED, CHAR, DATE, DATETIME, TIME, DECIMAL, BINARY, and others.

The CONVERT function in MySQL and SQL Server has different argument orders and different type names. The CAST function is the portable form for the type conversions that both support.

Oracle has no CONVERT function for types. It uses TO_NUMBER, TO_CHAR, and TO_DATE.

SELECT TO_NUMBER('42') FROM dual;          -- 42
SELECT TO_CHAR(42) FROM dual;              -- '42'
SELECT TO_DATE('2026-01-08', 'YYYY-MM-DD') FROM dual;

PostgreSQL has no CONVERT function for types. It uses CAST and the :: operator.


c. Implicit conversion and conversion failures

The database performs implicit conversions automatically when the context requires a type.

SELECT 1 + '2';  -- 3 in MySQL, error in PostgreSQL

In MySQL, the string '2' is implicitly converted to the number 2, and the addition succeeds. In PostgreSQL, the addition of an integer and a string is an error; the conversion must be explicit.

-- PostgreSQL
SELECT 1 + '2';
-- ERROR: operator does not exist: integer + unknown
SELECT 1 + '2'::integer;  -- 3

The implicit conversion rules differ between databases. PostgreSQL is strict; MySQL is permissive. The CAST function is the reliable way to convert because it is explicit and the same in every database.

The implicit conversion in a WHERE clause can produce unexpected results.

-- MySQL: the string is converted to a number
SELECT * FROM users WHERE id = '42';  -- works
SELECT * FROM users WHERE id = '42abc';  -- matches 42, not an error

In MySQL, '42abc' is converted to 42 because the conversion reads the leading digits and ignores the rest. This is surprising and can produce wrong results. The explicit CAST makes the behavior predictable.

The conversion of a NULL produces a NULL regardless of the target type.

SELECT CAST(NULL AS integer);  -- NULL
SELECT CAST(NULL AS text);     -- NULL
SELECT CAST(NULL AS date);     -- NULL

The conversion of an empty string to a number is an error in PostgreSQL and a zero in MySQL.

-- PostgreSQL
SELECT CAST('' AS integer);
-- ERROR: invalid input syntax for type integer: ""
-- MySQL
SELECT CAST('' AS SIGNED);  -- 0

The conversion of a string to a boolean is database-specific. PostgreSQL accepts 'true', 'false', 't', 'f', '1', '0'. MySQL accepts '1' and '0' as booleans and treats other strings as 0.

-- PostgreSQL
SELECT CAST('true' AS boolean);  -- true
SELECT CAST('1' AS boolean);     -- true
-- MySQL
SELECT CAST('true' AS UNSIGNED);  -- 0 (not a number)

The conversion of a date to a string uses the default format of the database.

-- PostgreSQL
SELECT CAST(CURRENT_DATE AS text);  -- '2026-01-08'
-- MySQL
SELECT CAST(CURRENT_DATE AS CHAR);  -- '2026-01-08'
-- SQL Server
SELECT CONVERT(varchar, GETDATE(), 23);  -- '2026-01-08'

The conversion of a timestamp to a date truncates the time.

SELECT CAST(NOW() AS date);  -- 2026-01-08

The conversion of a date to a timestamp sets the time to midnight.

SELECT CAST(CURRENT_DATE AS timestamp);  -- 2026-01-08 00:00:00

The conversion between numeric types can lose precision.

SELECT CAST(42.7 AS integer);        -- 43 (rounds)
SELECT CAST(42.7 AS numeric(3,1));   -- 42.7
SELECT CAST(42.7 AS numeric(3,0));   -- 43
SELECT CAST(1234.5 AS numeric(5,2)); -- 1234.50
SELECT CAST(1234.5 AS numeric(2,0)); -- error (overflow)

The numeric(p, s) type has p total digits and s decimal digits. A value that does not fit produces an error.


Complete Example Session

-- ============================================
-- PART 1: CAST STRING TO NUMBER
-- ============================================
SELECT CAST('42' AS integer);        -- 42
SELECT CAST('42.7' AS numeric);      -- 42.7
SELECT CAST('42.7' AS numeric(10,2)); -- 42.70
-- ============================================
-- PART 2: CAST NUMBER TO STRING
-- ============================================
SELECT CAST(42 AS text);             -- '42'
SELECT CAST(42.7 AS text);           -- '42.7'
-- ============================================
-- PART 3: CAST TO INTEGER ROUNDS
-- ============================================
SELECT CAST(42.4 AS integer);        -- 42
SELECT CAST(42.5 AS integer);        -- 43
SELECT CAST(42.6 AS integer);        -- 43
-- ============================================
-- PART 4: CAST STRING TO DATE
-- ============================================
SELECT CAST('2026-01-08' AS date);   -- 2026-01-08
SELECT CAST('2026-01-08 10:30' AS timestamp);
-- ============================================
-- PART 5: POSTGRESQL :: OPERATOR
-- ============================================
SELECT '42'::integer;                -- 42
SELECT 42::text;                     -- '42'
SELECT '2026-01-08'::date;           -- 2026-01-08
-- ============================================
-- PART 6: SQL SERVER CONVERT
-- ============================================
SELECT CONVERT(integer, '42');
SELECT CONVERT(varchar, 42);
SELECT CONVERT(varchar, GETDATE(), 23);
-- ============================================
-- PART 7: MYSQL CONVERT
-- ============================================
SELECT CONVERT('42', SIGNED);
SELECT CONVERT(42, CHAR);
SELECT CONVERT('2026-01-08', DATE);
-- ============================================
-- PART 8: IMPLICIT CONVERSION
-- ============================================
-- PostgreSQL: strict
SELECT 1 + '2'::integer;             -- 3
-- MySQL: permissive
SELECT 1 + '2';                      -- 3
-- ============================================
-- PART 9: CONVERSION FAILURE
-- ============================================
-- PostgreSQL
SELECT CAST('abc' AS integer);
-- ERROR: invalid input syntax for type integer: "abc"
-- ============================================
-- PART 10: SAFE CONVERSION WITH NULLIF
-- ============================================
SELECT CAST(NULLIF(value, '') AS integer) FROM data;
-- Empty string becomes NULL, then NULL

The ten parts covered casting a string to a number, a number to a string, the rounding behavior, casting to a date, the :: operator, CONVERT in SQL Server, CONVERT in MySQL, implicit conversion, conversion failure, and safe conversion.


Quick Reference

CAST Syntax

DatabaseSyntax
StandardCAST(expr AS type)
PostgreSQLexpr::type
MySQLCAST(expr AS type)
SQL ServerCAST(expr AS type)
OracleCAST(expr AS type)

CONVERT Syntax

DatabaseSyntax
SQL ServerCONVERT(type, expr [, style])
MySQLCONVERT(expr, type) or CONVERT(expr USING charset)
OracleNo CONVERT for types; use TO_* functions
PostgreSQLNo CONVERT for types; use CAST

Common Types

TypeDescription
integer / intWhole number
numeric(p,s)Fixed precision
decimal(p,s)Same as numeric
float / realFloating point
text / varcharString
char(n)Fixed-length string
dateDate
timestampDate and time
booleanTrue/false
uuidUUID

Conversion Behavior

FromToResult
'42'integer42
'42.7'integerError (PostgreSQL)
42.7integer43 (rounds)
42text'42'
'abc'integerError
NULLanyNULL
''integerError (PostgreSQL), 0 (MySQL)
'true'booleantrue (PostgreSQL)

SQL Server Date Styles

StyleFormat
23yyyy-mm-dd
101mm/dd/yyyy
103dd/mm/yyyy
112yyyymmdd
120yyyy-mm-dd hh:mi:ss
126ISO 8601

Best Practices

✅ Do This:

-- Use CAST for portability
SELECT CAST('42' AS integer);                                  -- ✅

-- Use explicit conversion in comparisons
WHERE id = CAST('42' AS integer);                              -- ✅

-- Use NULLIF for safe conversion
SELECT CAST(NULLIF(value, '') AS integer) FROM data;           -- ✅

-- Use numeric for exact decimal arithmetic
SELECT CAST(amount AS numeric(10,2)) FROM orders;              -- ✅

-- Use CONVERT with a style for dates in SQL Server
SELECT CONVERT(varchar, GETDATE(), 23);                        -- ✅

-- Cast one operand to avoid integer division
SELECT CAST(total AS numeric) / count FROM stats;              -- ✅

❌ Don’t Do This:

-- Don't rely on implicit conversion
WHERE id = '42';  -- may work or fail                            -- ⚠️

-- Don't convert a string that may not be a number
SELECT CAST(user_input AS integer);  -- error if not numeric     -- ❌

-- Don't use CONVERT in PostgreSQL
SELECT CONVERT(integer, '42');  -- no such function              -- ❌

-- Don't assume the date format
SELECT CAST('01/08/2026' AS date);  -- locale-dependent           -- ⚠️

-- Don't cast to a type that cannot hold the value
SELECT CAST(12345 AS numeric(2,0));  -- overflow                  -- ❌

-- Don't compare a number to a string without conversion
WHERE num_col = '42';  -- may not use the index                  -- ⚠️

-- Don't forget that CAST rounds when converting to integer
SELECT CAST(42.5 AS integer);  -- 43, not 42                    -- ⚠️

Common Pitfalls

PitfallWhy It HappensFix
Conversion errorString is not a numberValidate or use NULLIF
Wrong dateFormat mismatchUse ISO format
Rounded integerCAST roundsUse TRUNC or FLOOR
OverflowValue too large for typeUse a larger type
Implicit conversion surpriseDatabase rules differUse explicit CAST
CONVERT not foundDatabase does not have itUse CAST
Index not usedType mismatch in WHERECast the literal, not the column

Real-World Examples

1. String to Number

SELECT CAST(quantity AS integer) FROM order_items;

2. Number to String

SELECT 'Order #' || CAST(order_id AS text) FROM orders;

3. Date to String

SELECT CAST(order_date AS text) FROM orders;

4. String to Date

SELECT CAST('2026-01-08' AS date);

5. Timestamp to Date

SELECT CAST(created_at AS date) FROM users;

6. Percentage

SELECT CAST(100.0 * successful / NULLIF(total, 0) AS numeric(5,2))
FROM stats;

7. Safe Conversion

SELECT CAST(NULLIF(value, '') AS integer) FROM data;

8. SQL Server Date Format

SELECT CONVERT(varchar, GETDATE(), 23);

9. Boolean to String

SELECT CAST(is_active AS text) FROM users;

10. Numeric Precision

SELECT CAST(price AS numeric(10,2)) FROM products;

Visual

CAST Function

┌─────────────────────────────────────────────────────────────┐
│  CAST(expression AS type)                                   │
│                                                             │
│  CAST('42' AS integer)       → 42                           │
│  CAST(42 AS text)            → '42'                         │
│  CAST('2026-01-08' AS date)  → 2026-01-08                   │
│  CAST(42.7 AS integer)       → 43 (rounds)                  │
│  CAST(42.7 AS numeric(10,2)) → 42.70                        │
│                                                             │
│  PostgreSQL shorthand:                                      │
│  '42'::integer               → 42                           │
│  42::text                    → '42'                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

CAST vs CONVERT

┌─────────────────────────────────────────────────────────────┐
│  CAST (standard)                                            │
│  CAST(expr AS type)                                         │
│  Supported by: PostgreSQL, MySQL, SQL Server, Oracle, SQLite│
│                                                             │
│  CONVERT (SQL Server)                                       │
│  CONVERT(type, expr, style)                                 │
│  The style argument formats dates                           │
│                                                             │
│  CONVERT (MySQL)                                            │
│  CONVERT(expr, type)                                        │
│  The argument order is reversed                             │
│                                                             │
│  Use CAST for portability.                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Conversion Failure

┌─────────────────────────────────────────────────────────────┐
│  CAST('42' AS integer)  → 42                                │
│  CAST('abc' AS integer) → ERROR                             │
│                                                             │
│  The error aborts the query.                                │
│                                                             │
│  Safe conversion:                                           │
│  CAST(NULLIF(value, '') AS integer)                         │
│  → converts empty string to NULL, then NULL                 │
│                                                             │
│  Or use a CASE:                                             │
│  CASE WHEN value ~ '^[0-9]+$'                               │
│       THEN CAST(value AS integer)                           │
│       ELSE NULL END                                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Numeric Precision

┌─────────────────────────────────────────────────────────────┐
│  numeric(p, s)                                              │
│  p = total digits                                           │
│  s = decimal digits                                         │
│                                                             │
│  numeric(5,2)  → 123.45                                     │
│  numeric(5,2)  → 1234.5  (error: 5 digits, 1 decimal)       │
│  numeric(10,2) → 12345678.90                                │
│                                                             │
│  CAST(1234.5 AS numeric(5,2))  → 1234.50                    │
│  CAST(1234.5 AS numeric(3,0))  → error (overflow)           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Summary

ItemValue
StandardCAST(expr AS type)
PostgreSQL shorthandexpr::type
SQL ServerCONVERT(type, expr, style)
MySQLCONVERT(expr, type)
OracleTO_NUMBER, TO_CHAR, TO_DATE
String to numberCAST('42' AS integer)
Number to stringCAST(42 AS text)
String to dateCAST('2026-01-08' AS date)
RoundingCAST(42.7 AS integer) → 43
NULL conversionCAST(NULL AS type) → NULL
FailureError on invalid input
Safe conversionCAST(NULLIF(value, '') AS integer)

Key takeaways:

  • CAST is the standard conversion function. It is supported by every major database. The syntax is CAST(expression AS type). The PostgreSQL :: operator is a shorthand for CAST.
  • CONVERT is not standard. SQL Server uses CONVERT(type, expr, style), and MySQL uses CONVERT(expr, type). The argument order and the type names differ. Use CAST for portability.
  • Implicit conversion is database-specific. PostgreSQL is strict; MySQL is permissive. The CAST function is explicit and predictable. Use it when the conversion matters.
  • Conversion to integer rounds. CAST(42.7 AS integer) is 43. The rounding is half away from zero for the numeric type. Use TRUNC or FLOOR if the fractional part should be discarded.
  • Conversion from a string can fail. A string that is not a valid number produces an error. The NULLIF pattern converts an empty string to NULL before the cast, which prevents the error.
  • The numeric(p, s) type has a fixed precision. A value that does not fit produces an error. Choose p and s large enough for the values.
  • The date format depends on the database. Use the ISO format YYYY-MM-DD for the most reliable conversion. SQL Server’s CONVERT with style 23 produces the ISO format.

Remember: Type conversion is how SQL handles values that do not have the type the context requires. The CAST function is the standard, and the explicit form is the predictable form. The implicit conversions differ between databases; the explicit conversions are the same. Use CAST for portability. Use CONVERT with a style for date formatting in SQL Server. Use NULLIF for safe conversion. And remember that a conversion can fail—the failure is the database telling you that the value is not what the type expects.



Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!