Pure SQL Method with RECURSIVE CTE (no STRING_AGG or STRING_SPLIT needed)
IntuitionWe want to convert each word in a given text so that its first letter is capitalized and its other letters are lowercase. Additionally, any hyphenated
# Intuition
We want to convert each word in a given text so that its first letter is capitalized and its other letters are lowercase. Additionally, any hyphenated sub-words should be treated separately (e.g., “web-based” → “Web-Based”). We can achieve this by walking through each character in content_text and deciding, based on the previous character, whether to uppercase or lowercase the current character.


# Approach
1. Extract Table Data: a CTE
We select the content_**i**d (aliased as **i**), the content_**t**ext (aliased as **t**), and the **l**ength of content_text (aliased as **l**).

2. Generate One Row Per Character: b CTE
• Starting from position 1, we recursively union all subsequent positions until we cover the entire length of the text.
• Each row in b contains:
**i**: The content **i**d.
**r**: The current **r**ow character index (1-based).
**c**: The single **c**haracter at position r.
**l**: The string **l**ength.
**t**: The full **t**ext for reference.

3. Determine Case: u CTE
• We join b to itself (aliased as w) on the previous character (r-1) to check if the preceding character is a space or a hyphen.
• If the preceding character is " " (space) or "-", we uppercase the current character; otherwise, we lowercase it.
• This logic ensures that each new “word” or “sub-word” after a space or hyphen gets capitalized.

4. Rebuild the String: s CTE
• We start from a row where r = 1 (the first character). However, note that the code effectively seeds from r = 0 in the condition, then steps forward.
• We recursively concatenate the characters (in their correct case) one by one until we form the entire string.
• Eventually, for each content_id, we end up with a fully transformed string where each position has the correct casing.

5. Final Output
We select from a (original rows) and join on s (the rebuilt string), matching on the condition that s.r = a.l (i.e., we only take the final concatenated string when we’ve reached the last character).

# Complexity
- Time complexity:
If 𝑁 is the number of rows in the user_content table and 𝐿 is the maximum length of content_text, then the CTE that enumerates characters (b) and the following transformations (u, s) each process 𝑂(𝑁×𝐿) items. Hence, the overall time complexity is 
𝑂(𝑁×𝐿).

- Space complexity:
We store intermediate results for every character of every row in the CTEs, which is also 𝑂(𝑁×𝐿). The final output table retains the transformed strings, adding another 𝑂(𝑁×𝐿) space requirement at most.

# Code
```mysql []
WITH RECURSIVE
 a(i,t,l) AS (SELECT content_id,content_text,LENGTH(content_text) FROM user_content)
,b(i,r,c,l,t) AS (
    SELECT i,1,SUBSTRING(t,1,1),l,t FROM a
    UNION ALL
    SELECT i,r+1,SUBSTRING(t,r+1,1),l,t FROM b WHERE r+1<=l
)
,u(i,r,n) AS (
    SELECT b.i,b.r,(CASE WHEN COALESCE(w.c,' ') IN (' ', '-') THEN UPPER(b.c) ELSE LOWER(b.c) END)
    FROM b LEFT JOIN b w ON b.i=w.i AND b.r=w.r+1
)
,s(i,n,r) AS (
    SELECT i,CAST('' AS CHAR(8000)),0
    FROM u WHERE r=1
    UNION ALL
    SELECT u.i,CONCAT(s.n,u.n),u.r
    FROM u INNER JOIN s ON u.i=s.i AND u.r=s.r+1
)
SELECT a.i AS content_id,a.t AS original_text,s.n AS converted_text
FROM a INNER JOIN s ON s.i=a.i AND s.r=a.l
ORDER BY 1
```

```mssql []
WITH
 a(i,t,l) AS (SELECT content_id,content_text,LEN(content_text) FROM user_content)
,b(i,r,c,l,t) AS (
    SELECT i,1,SUBSTRING(t,1,1),l,t FROM a
    UNION ALL
    SELECT i,r+1,SUBSTRING(t,r+1,1),l,t FROM b WHERE r+1<=l
)
,u(i,r,n) AS (
    SELECT b.i,b.r,(CASE WHEN COALESCE(w.c,' ') IN (' ', '-') THEN UPPER(b.c) ELSE LOWER(b.c) END)
    FROM b LEFT JOIN b w ON b.i=w.i AND b.r=w.r+1
)
,s(i,n,r) AS (
    SELECT i,CAST('' AS NVARCHAR(MAX)),0
    FROM u WHERE r=1
    UNION ALL
    SELECT u.i,CONCAT(s.n,u.n),u.r
    FROM u INNER JOIN s ON u.i=s.i AND u.r=s.r+1
)
SELECT a.i AS content_id,a.t AS original_text,s.n AS converted_text
FROM a INNER JOIN s ON s.i=a.i AND s.r=a.l
ORDER BY 1
```

```postgresql []
WITH RECURSIVE
 a(i,t,l) AS (SELECT content_id,content_text,LENGTH(content_text) FROM user_content)
,b(i,r,c,l,t) AS (
    SELECT i,1,SUBSTRING(t,1,1),l,t FROM a
    UNION ALL
    SELECT i,r+1,SUBSTRING(t,r+1,1),l,t FROM b WHERE r+1<=l
)
,u(i,r,n) AS (
    SELECT b.i,b.r,(CASE WHEN COALESCE(w.c,' ') IN (' ', '-') THEN UPPER(b.c) ELSE LOWER(b.c) END)
    FROM b LEFT JOIN b w ON b.i=w.i AND b.r=w.r+1
)
,s(i,n,r) AS (
    SELECT i,'',0
    FROM u WHERE r=1
    UNION ALL
    SELECT u.i,CONCAT(s.n,u.n),u.r
    FROM u INNER JOIN s ON u.i=s.i AND u.r=s.r+1
)
SELECT a.i AS content_id,a.t AS original_text,s.n AS converted_text
FROM a INNER JOIN s ON s.i=a.i AND s.r=a.l
ORDER BY 1
```

```oracle []
WITH
 a(i,t,l) AS (SELECT content_id,content_text,LENGTH(content_text) FROM user_content)
,b(i,r,c,l,t) AS (
    SELECT i,1,SUBSTR(t,1,1),l,t FROM a
    UNION ALL
    SELECT i,r+1,SUBSTR(t,r+1,1),l,t FROM b WHERE r+1<=l
)
,u(i,r,n) AS (
    SELECT b.i,b.r,(CASE WHEN COALESCE(w.c,' ') IN (' ', '-') THEN UPPER(b.c) ELSE LOWER(b.c) END)
    FROM b LEFT JOIN b w ON b.i=w.i AND b.r=w.r+1
)
,s(i,n,r) AS (
    SELECT i,CAST('' AS VARCHAR2(4000)),0
    FROM u WHERE r=1
    UNION ALL
    SELECT u.i,CONCAT(s.n,u.n),u.r
    FROM u INNER JOIN s ON u.i=s.i AND u.r=s.r+1
)
SELECT a.i AS content_id,a.t AS original_text,s.n AS converted_text
FROM a INNER JOIN s ON s.i=a.i AND s.r=a.l
ORDER BY 1
```
['MySQL', 'Oracle', 'MS SQL Server', 'PostgreSQL']