加入和过滤一对多关系
Joining and filtering one-to-many relationship
我需要一些有关 SQL 查询的最佳结构的帮助。我有这样的模型:
我正在尝试 tables NON_NATURAL_PERSON
和 NNP_NAME
之间的某种连接。因为我在 table NNP_NAME
中有很多人的名字,所以我不能一对一 SELECT * from NON_NATURAL_PERSON inner join NNP_NAME
等。这样我会为一个人的每个名字获得额外的行.
table秒内的数据:
如何扩展此查询以获取下图中标记为红色的行?我想要的查询条件是:仅当存在时才始终加入 typeA 的名称。如果不是,则加入类型 B 的名称。如果两者都不存在 typeC.
的连接名称
SELECT nnp.ID, name.NAME, name.TYPE
FROM NON_NATURAL_PERSON nnp
INNER JOIN NNP_NAME name ON (name.NON_NATURAL_PERSON = nnp.ID)
如果类型的拼写与书写的完全一致(typeA、typeB、typeC),那么您可以使用 MIN() 函数:
SELECT NON_NATURAL_PERSON, MIN(type) AS min_type
FROM NNP_NAME
GROUP BY NON_NATURAL_PERSON
如果您还需要用户名,可以使用此查询:
SELECT
n1.NON_NATURAL_PERSON AS ID,
n1.Name,
n1.Type
FROM
NNP_NAME n1 LEFT JOIN NNP_NAME n2
ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON
AND n1.Type > n2.type
WHERE
n2.type IS NULL
请看这个fiddle。如果类型不是按字面顺序排序,请更改此行:
AND n1.Type > n2.type
有了这个:
AND FIELD(n1.Type, 'TypeA', 'TypeB', 'TypeC') >
FIELD(n2.type, 'TypeA', 'TypeB', 'TypeC')
MySQL FIELD(str, str1, str2, ...) 函数 returns str 在 str1, str2, ... 列表中的索引(位置),如果为 0未找到 str。您想要为每个 NON_NATURAL_PERSON 获取按类型排序的 "first" 记录。有多种获取此信息的方法,我选择了自连接:
ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON
AND n1.Type > n2.type -- or filed function
WHERE 条件:
WHERE n2.type IS NULL
这将 return 连接未成功的所有行 - 当不存在小于 n1.type 的 n2.type 时,连接将不会成功 - 它会 return第一条记录。
编辑
如果你想要一个独立于平台的解决方案,避免创建新表,你可以使用 CASE WHEN,只需更改
AND n1.Type > n2.Type
与
AND
CASE
WHEN n1.Type='TypeA' THEN 1
WHEN n1.Type='TypeB' THEN 2
WHEN n1.Type='TypeC' THEN 3
END
>
CASE
WHEN n2.Type='TypeA' THEN 1
WHEN n2.Type='TypeB' THEN 2
WHEN n2.Type='TypeC' THEN 3
END
缺少一条信息。你说:
Always join name of typeA only if exists. If not, join name of typeB. If neither exists join name of typeC.
但是你没有说明为什么你更喜欢typeA而不是typeB。此信息不包含在您的数据中。
在@fthiella 的回答中,要么假定字典顺序,要么使用 FIELD
给出任意顺序。这也是为什么需要使用 table nnp_name
进行两次连接的原因。
您可以通过添加 table name_type (id, name, order)
并将类型列更改为包含 id 来解决此问题。这将允许您以干净的方式添加缺失的信息。
通过与此新 table 的额外连接,您将能够为每一行获得首选 nnp_name。
我需要一些有关 SQL 查询的最佳结构的帮助。我有这样的模型:
我正在尝试 tables NON_NATURAL_PERSON
和 NNP_NAME
之间的某种连接。因为我在 table NNP_NAME
中有很多人的名字,所以我不能一对一 SELECT * from NON_NATURAL_PERSON inner join NNP_NAME
等。这样我会为一个人的每个名字获得额外的行.
table秒内的数据:
如何扩展此查询以获取下图中标记为红色的行?我想要的查询条件是:仅当存在时才始终加入 typeA 的名称。如果不是,则加入类型 B 的名称。如果两者都不存在 typeC.
SELECT nnp.ID, name.NAME, name.TYPE
FROM NON_NATURAL_PERSON nnp
INNER JOIN NNP_NAME name ON (name.NON_NATURAL_PERSON = nnp.ID)
如果类型的拼写与书写的完全一致(typeA、typeB、typeC),那么您可以使用 MIN() 函数:
SELECT NON_NATURAL_PERSON, MIN(type) AS min_type
FROM NNP_NAME
GROUP BY NON_NATURAL_PERSON
如果您还需要用户名,可以使用此查询:
SELECT
n1.NON_NATURAL_PERSON AS ID,
n1.Name,
n1.Type
FROM
NNP_NAME n1 LEFT JOIN NNP_NAME n2
ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON
AND n1.Type > n2.type
WHERE
n2.type IS NULL
请看这个fiddle。如果类型不是按字面顺序排序,请更改此行:
AND n1.Type > n2.type
有了这个:
AND FIELD(n1.Type, 'TypeA', 'TypeB', 'TypeC') >
FIELD(n2.type, 'TypeA', 'TypeB', 'TypeC')
MySQL FIELD(str, str1, str2, ...) 函数 returns str 在 str1, str2, ... 列表中的索引(位置),如果为 0未找到 str。您想要为每个 NON_NATURAL_PERSON 获取按类型排序的 "first" 记录。有多种获取此信息的方法,我选择了自连接:
ON n1.NON_NATURAL_PERSON = n2.NON_NATURAL_PERSON
AND n1.Type > n2.type -- or filed function
WHERE 条件:
WHERE n2.type IS NULL
这将 return 连接未成功的所有行 - 当不存在小于 n1.type 的 n2.type 时,连接将不会成功 - 它会 return第一条记录。
编辑
如果你想要一个独立于平台的解决方案,避免创建新表,你可以使用 CASE WHEN,只需更改
AND n1.Type > n2.Type
与
AND
CASE
WHEN n1.Type='TypeA' THEN 1
WHEN n1.Type='TypeB' THEN 2
WHEN n1.Type='TypeC' THEN 3
END
>
CASE
WHEN n2.Type='TypeA' THEN 1
WHEN n2.Type='TypeB' THEN 2
WHEN n2.Type='TypeC' THEN 3
END
缺少一条信息。你说:
Always join name of typeA only if exists. If not, join name of typeB. If neither exists join name of typeC.
但是你没有说明为什么你更喜欢typeA而不是typeB。此信息不包含在您的数据中。
在@fthiella 的回答中,要么假定字典顺序,要么使用 FIELD
给出任意顺序。这也是为什么需要使用 table nnp_name
进行两次连接的原因。
您可以通过添加 table name_type (id, name, order)
并将类型列更改为包含 id 来解决此问题。这将允许您以干净的方式添加缺失的信息。
通过与此新 table 的额外连接,您将能够为每一行获得首选 nnp_name。