Dewsworld
Dewsworld

Reputation: 14033

CREATE TYPE on MySQL

I couln't create a new data type on MySQL. Query is given below

CREATE TYPE PERSON AS OBJECT
(NAME       VARCHAR (30),
 SSN        VARCHAR (9));

How can I do that on MySQL

Upvotes: 19

Views: 27901

Answers (3)

Sam Hughes
Sam Hughes

Reputation: 785

The other two answers are 100% correct, both that you cannot define new scalar-tuple values, and that JSON as a native type gets you almost there.

I have three suggestions. First, a proposal for how to enforce a specific JSON schema on value, supported by getters/setters. A second possible solution would by CTE's, though that involves some additional work on the writing end, and is not a replacement for true custom types. A third approach, somewhat of a hybrid of the first two suggestions, would involve getters/setters that encapsulate a subquery lookup.

Please, before you read further, the following represents napkin-draft quality sketches. Expect nothing better. I haven't worked with MySQL since late 2020.

First up, a constructor/getter/setter approach, though implementing this would likely take a bit of work, and even well-designed indexing can't get it to compete with native columns on lookup performance, and it'll always take up more space in chunk/page/disk but it's a 90% solution -- much like how one implements struct methods in C, if you do it, it's solely for namespace organization, and it will be clumsy.

delimiter $$;
create function contact_encode(fname text, lname text, phone text, email text)
returns JSON
deterministic
begin
    /* validation stuff here? like maybe you care that they're not null
       and/or sane values for names and phone numbers and email addresses?
     */
    return json_object(
        'firstName', fname,
        'lastName', lname,
        'contactMethod', json_array(
            json_object(
                'type','phone',
                'value',phone
            ),
            json_object(
                'type','email',
                'value',email
            )
        )
    );
end$$
delimiter ;$$
/*  Yep, this approach probably actually sucks

    I was going to suggest something like contact_decode(JSON)->values...,
    but I forgot that you can't return multiple values from a function.
    That's the irony; it'd be easier to use JSON for custom types in
    languages that already support return tuples and custom types as relations. 

    Grrrrr
 */

Err, yep. That's probably the closest you can get to custom types using MySQL. Hypothetically a set of getter/setter functions like the following would actually conceivably improve on the existing MySQL 8 API for JSON values/columns. This is, again purely hypothetically, an example of a setter with encoded behaviors that provides some level of encapsulated logic:

create function contact_get_name(contact JSON)
.....return concat(contact->>'firstName', ' ',contact->>'lastName')
.....
create function contact_set_name(contact JSON, value text)
....return json_replace(
        contact, 
        '$.firstName', substring_index(value, ' ', 1),
        '$.lastName'. substring_index(value, ' ', -1)
    )
.....

Issues abound. If it helps, typing wasn't ever a serious constraint on me as a MySQL dev. Now that I work with an outfit that uses PostgreSQL as the default, custom types are amazing (return rowtype, I'm looking at you), but because we hadn't migrated from MySQL 5.x to 8.x, I didn't get to play with CTE's before PostgreSQL. That said, the following might not translate directly to MySQL.

Suppose a table called 'blog_user' has the columns (id, name, phone, email, username, password, blah-blah-blah.....), a 'custom type' use of the table in a query of a table called post (id, author_id, title, ....) might look like:

with author as (
    select
        id,
        substring_index(name, ' ', 1) as first_name,
        substring_index(name, ' ', -1) as last_name,
        email,
        concat('###-###-', right(phone, 4)) as phone
    from blog_user
) select
    concat(first_name, ' ', left(last_name, 1), '.') as name,
    title,
    yada-yada.....
from author, post
where author.id = post.author_id
and case 
    when @requested_blog_post is not null
        then post.id = @requested_blog_post
    when @title_search_term is not null
        then post.title like concat('%',@title_search_term,'%')
    else false
end

It achieves the desired impact, and as a partial join, it's actually going to be pretty much transparent, performance-wise...assuming good indexes on any CTE source columns used in the core query's filter.

Performance-wise, the latter approach, adding CTE's to create subqueries to partially join in on specific attributes, is going to be far-and-away superior to the JSON approach, while the JSON approach is arguably more ergonomic to some, especially if you're accustomed to working with JSON in MySQL anyway.

A third solution would be to define custom getter/setter functions that receive an id, and which return the value for the column on that id, like so:

create function post_get_author_name(requested_post int)
....
return (
    with author as (
        ....
    ) select 
        name 
    from author, post
    where author.id = post.author_id
    and post.id = requested_post
    limit 1 /*completely unnecessary in this case, but it's a thing I do anyway*/
)
....

The difficulty with that approach is that, well, it suggests you're going to call a bunch of those getters in the same query. That's objectively worse performance-wise than the local CTE solution, and it's possibly worse performance than the same getter/setter approach with row-local JSON.

The take-away is the following: sorry you can't have custom types. There are some approximations, and I wouldn't have even understood your pain a few months ago, but my condolences. Have some possibly workable approximations.

Upvotes: 0

Hauzer Lee
Hauzer Lee

Reputation: 81

You can use JSON data type now. MySQL supports the native JSON data type since version 5.7. 8.

Upvotes: 4

user149341
user149341

Reputation:

You cannot. MySQL doesn't have user-defined types. (At least, not in current versions.)

Upvotes: 27

Related Questions