Context: I'm trying to build a function to apply title case to a string.
Instead of answering directly the question - I rather want to address what I believe drove the question to be asked in first place
It is obvious from my experience here on SO that frequently OPs ask questions of literally asking to help them to go wrong direction! in many cases it is sad experience as you understand that you are not doing good help to such person but rather quite opposite. I am guilty to be part of it many times because it is not always really clear what real use case is, so there is no much options to help rather then to answer exact question as it is asked
I think in this case - above question has good hint of real purpose / use-case - so as I already said I want to answer it (the use-case)
You don't really need to do loop in most cases - you rather should try to achieve thing(s) in a sql way - set-based!
So, the hint is in below statement
Context: I'm trying to build a function to apply title case to a string.
The simple way to handle title case function is as below
#standardSQL
CREATE TEMP FUNCTION TitleCase(text STRING) AS ((
SELECT STRING_AGG(UPPER(SUBSTR(part, 1, 1)) || SUBSTR(part, 2), ' ' ORDER BY OFFSET)
FROM UNNEST(SPLIT(text, ' ')) part WITH OFFSET
));
SELECT text,
TitleCase(text) transformed_text
FROM `project.dataset.table`
you can test above with dummy data as in below example
#standardSQL
CREATE TEMP FUNCTION TitleCase(text STRING) AS ((
SELECT STRING_AGG(UPPER(SUBSTR(part, 1, 1)) || SUBSTR(part, 2), ' ' ORDER BY OFFSET)
FROM UNNEST(SPLIT(text, ' ')) part WITH OFFSET
));
WITH `project.dataset.table` AS (
SELECT 1 id, "google cloud platform" AS text UNION ALL
SELECT 2, "o'brian"
)
SELECT text,
TitleCase(text) transformed_text
FROM `project.dataset.table`
with output as below
Row text transformed_text
1 google cloud platform Google Cloud Platform
2 o'brian O'brian
As you can see, your initial approach with using space as a delimiter to split text is not the best way - O'brian didn't get b capitalized
To address this - you can use below approach
#standardSQL
CREATE TEMP FUNCTION TitleCase(text STRING) AS ((
SELECT STRING_AGG(char, '' ORDER BY OFFSET)
FROM (
SELECT IF(REGEXP_CONTAINS(LAG(char) OVER(ORDER BY OFFSET), r'\w'), char, UPPER(char)) char, OFFSET
FROM UNNEST(SPLIT(text, '')) char WITH OFFSET
)
));
SELECT text,
TitleCase(text) transformed_text
FROM `project.dataset.table`
Now, when applied to same dummy data - result is more appropriate
Row text transformed_text
1 google cloud platform Google Cloud Platform
2 o'brian O'Brian
Note: above is just one(or rather two) examples of how to avoid noneffective cursor based processing and rather do all in one (set-based) turn