15

我无法在 MySQL 上创建新的数据类型。查询如下

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

我怎么能在 MySQL 上做到这一点

4

3 回答 3

23

你不能。MySQL 没有用户定义的类型。(至少,不是在当前版本中。)

于 2012-04-22T07:38:26.153 回答
4

您现在可以使用 JSON 数据类型。MySQL 从 5.7 版本开始支持原生 JSON 数据类型。8.

于 2020-09-01T03:27:45.663 回答
0

其他两个答案都是 100% 正确的,你不能定义新的标量元组值,而 JSON 作为原生类型让你几乎可以做到。

我有三个建议。首先,关于如何对值强制执行特定 JSON 模式的建议,由 getter/setter 支持。第二种可能的解决方案是 CTE,尽管这涉及到一些额外的写作工作,并且不能替代真正的自定义类型。第三种方法,在某种程度上是前两种建议的混合体,将涉及封装子查询查找的 getter/setter。

请在您进一步阅读之前,以下代表餐巾草稿质量草图。没有比这更好的了。自 2020 年底以来,我没有使用过 MySQL。

首先,构造函数/getter/setter 方法,尽管实现它可能需要一些工作,即使设计良好的索引也无法使其在查找性能上与本机列竞争,而且它总是会占用更多块/页面/磁盘中的空间,但它是 90% 的解决方案——就像在 C 中实现 struct 方法的方式一样,如果你这样做,它只是用于命名空间组织,而且会很笨拙。

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
 */

错,是的。这可能是您可以使用 MySQL 获得的最接近自定义类型的方法。假设一组像下面这样的 getter/setter 函数实际上可以改进现有的 MySQL 8 API for JSON 值/列。再次纯粹假设,这是一个具有编码行为的 setter 示例,它提供了某种程度的封装逻辑:

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)
    )
.....

问题比比皆是。如果有帮助,作为 MySQL 开发人员,打字从来都不是对我的严重限制。现在我与使用 PostgreSQL 作为默认值的装备一起工作,自定义类型非常棒(返回行类型,我在看着你),但是因为我们还没有从 MySQL 5.x 迁移到 8.x,所以我没有在 PostgreSQL 之前不能玩 CTE。也就是说,以下内容可能不会直接转换为 MySQL。

假设一个名为“blog_user”的表具有列(id、name、phone、email、username、password、blah-blah-blah.....),在表的查询中使用该表的“自定义类型”称为 post (id, author_id, title, ....) 可能如下所示:

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

它实现了预期的影响,并且作为部分连接,它实际上将非常透明,性能方面......假设核心查询过滤器中使用的任何 CTE 源列都有良好的索引。

在性能方面,后一种方法,添加 CTE 来创建子查询以部分加入特定属性,将远远优于 JSON 方法,而 JSON 方法可以说对某些人来说更符合人体工程学,特别是如果你'无论如何都习惯于在 MySQL 中使用 JSON。

第三种解决方案是定义接收 id 的自定义 getter/setter 函数,并返回该 id 上列的值,如下所示:

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*/
)
....

这种方法的困难在于,它表明您将在同一个查询中调用一堆这些 getter。这在性能方面客观上比本地 CTE 解决方案更差,而且它的性能可能比使用行本地 JSON 的相同 getter/setter 方法更差。

要点如下:抱歉,您不能有自定义类型。有一些近似值,几个月前我什至无法理解你的痛苦,但我表示哀悼。有一些可能可行的近似值。

于 2021-08-04T14:38:26.670 回答