You are correct that you cannot update individual fields of a frozen UDT column but you can update the whole column value. You do not need to delete the previous record. It's fine to update the fields directly. Let me illustrate with an example I created on Astra.
Here is a user-defined type that stores a user's address:
CREATE TYPE address (
number int,
street text,
city text,
zip int
)
and here is the definition for the table of users:
CREATE TABLE users (
name text PRIMARY KEY,
address frozen<address>
)
In this table, there is one user with their address stored as:
cqlsh> SELECT * FROM users ;
name | address
-------+----------------------------------------------------------------
alice | {number: 100, street: 'Main Rd', city: 'Melbourne', zip: 3000}
Let's say that the street number is incorrect. If we try to update just the street number field with:
cqlsh> UPDATE users SET address = {number: 456} WHERE name = 'alice';
We'll end up with an address that only has the street number and nothing else:
cqlsh> SELECT * FROM users ;
name | address
-------+----------------------------------------------------
alice | {number: 456, street: null, city: null, zip: null}
This is because the whole value (not just the street number field) got overwritten by the update. The correct way to update the street number is to explicitly set a value for all the fields of the address with:
cqlsh> UPDATE users SET address = {number: 456, street: 'Main Rd', city: 'Melbourne', zip: 3000} WHERE name = 'alice';
so we end up with:
cqlsh> SELECT * FROM users ;
name | address
-------+----------------------------------------------------------------
alice | {number: 456, street: 'Main Rd', city: 'Melbourne', zip: 3000}
Cheers!