性能问题:一种更好的方法:“先案例,先定位,然后再分组”

时间:2019-02-13 04:29:29

标签: mysql

我有以下两个表field_allowedperson

field_allowed

#person_id, field, 
1         ,name
1         ,email
1         ,phone
2         ,name
2         ,phone
3         ,phone

#person_id, name, email,           phone
1         , Mary, 123@example.com, 12345671
2         , John, 124@example.com, null
3         , Jack, 125@example.com, 12345673

我想要以下结果,对人员数据的访问控制:

#person_id, name, email,           phone
1         , Mary, 123@example.com, 12345671
2         , John, N/A            , null
3         , N/A , N/A            , 12345673

我只找到一种愚蠢的方法来实现此输出

SELECT 
    person.person_id,
    CASE
        WHEN LOCATE('name', GROUP_CONCAT(DISTINCT field)) THEN person.name
        ELSE 'N/A'
    END AS name,
    CASE
        WHEN LOCATE('email', GROUP_CONCAT(DISTINCT field)) THEN person.email
        ELSE 'N/A'
    END AS email,
    CASE
        WHEN LOCATE('phone', GROUP_CONCAT(DISTINCT field)) THEN person.phone
        ELSE 'N/A'
    END AS phone
FROM
    person
        JOIN
    field_allowed ON field_allowed.person_id = person.person_id
GROUP BY person.person_id

我发现GROUP_CONCATLOCATE的使用似乎太脏了,必须有一种更好的方法。

因此,我想问一下是否有更好的方法可以进行上述操作?我可以控制数据库架构,因此可以更改架构也有帮助。

编辑:

请注意,未找到时,必须显示'N / A',并且名称可以是<3 个字符。因此答案MAX(CASE WHEN f.field = 'name' THEN name ELSE '' END) AS name)将无法显示某些名称。

1 个答案:

答案 0 :(得分:1)

利用MAX中的NULL和非空字符串将返回非空字符串的事实,您可以使用条件聚合来获得所需的结果。如果没有可用值,MAX将返回NULL,并且COALESCE可用于将该值转换为N/A

SELECT p.person_id,
       COALESCE(MAX(CASE WHEN f.field = 'name' THEN name END), 'N/A') AS name,
       COALESCE(MAX(CASE WHEN f.field = 'email' THEN email END), 'N/A') AS email,
       COALESCE(MAX(CASE WHEN f.field = 'phone' THEN phone END), 'N/A') AS phone
FROM person p
JOIN field_allowed f ON f.person_id = p.person_id
GROUP BY p.person_id

输出:

person_id   name    email           phone
1           Mary    123@example.com 12345671
2           John    N/A             null
3           N/A     N/A             12345673

Demo on dbfiddle