mysql - 将外部联接应用于复杂语句
mysql - Applying an outer join to a complex statement
我整理了一个查询来提取人们的名字,优先考虑在查看页面的人的 language/writing 脚本中写入的那个名字的版本。
我之前遇到过遗漏记录的问题,post就此提出了一个问题 here. I received an answer 建议使用 CASE 语句并应用分数根据首选 language/script。我已经得到了排名,它允许返回正确数量的记录(现在没有丢失的记录)。见下文:
SELECT
people.person_id,
names.name,
CASE
WHEN people.person_default_name_id=names.name_id AND language_scripts.script_id = :user_script_id THEN 3
WHEN names.language_id = :user_language_id THEN 2
WHEN language_scripts.script_id = :user_script_id THEN 1
ELSE 0
END as score
FROM
`people`
LEFT JOIN
`names` ON names.person_id=people.person_id
LEFT JOIN
`languages` ON names.language_id = languages.language_id
LEFT JOIN
`language_scripts` ON languages.language_id = language_scripts.language_id
GROUP BY
people.person_id
ORDER BY
names.name ASC
我现在遇到的麻烦是,因为我只需要每个人一个结果(因此 GROUP BY),它只是拉出每个人遇到的第一条记录。我需要能够使 "score" 起作用,并且只提取具有最高可用分数(可能是 3、2、1 或 0)的记录——每个人的最高分数记录。
最初 post 中的建议是使用外部查询,但我不确定如何在此处应用它。有什么想法吗?
编辑:这个 fiddle 显示了一个示例,它提取了所有记录及其分数:http://sqlfiddle.com/#!9/54ce8/13 - 我想要做的是只提取每个 [= =27=]得分最高。在这个例子中,我想要一个 table 和 Jorge 和 Alejandro 只是因为他们是两个中得分最高的名字。
我只能想到一种方法来实现这一点。在您当前的工作查询中结合使用 GROUP_CONCAT
和 SUBSTRING_INDEX
。下面的示例查询:
SELECT person_id,
SUBSTRING_INDEX(GROUP_CONCAT(a.name ORDER BY a.score DESC),',',1) sname,
SUBSTRING_INDEX(GROUP_CONCAT(a.score ORDER BY a.score DESC),',',1) max_score FROM
(SELECT people.person_id,
names.name,
CASE
WHEN people.person_default_name_id=names.name_id AND language_scripts.script_id = '1' THEN 3
WHEN names.language_id = '1' THEN 2
WHEN language_scripts.script_id = '1' THEN 1
ELSE 0
END AS score
FROM `people`
LEFT JOIN `names` ON names.person_id=people.person_id
LEFT JOIN `languages` ON names.language_id = languages.language_id
LEFT JOIN `language_scripts` ON languages.language_id = language_scripts.language_id) a
GROUP BY person_id;
我也在 fiddle 中测试了查询 http://sqlfiddle.com/#!9/54ce8/33
一点解释:
GROUP_CONCAT
在名称和分数上添加 ORDER BY
条件 - 请注意 ORDER BY
在两个 GROUP_CONCAT
.[=28= 中必须相同]
SUBSTRING_INDEX
获取字段中以逗号 (,) 分隔的第一个值。
return score
重要吗?或者目标只是return一个满足score=3条件的name
,如果不存在,满足条件的return一个name
对于分数=2,否则...
一种方法是进行条件聚合,当满足条件时 return 值为 name
,否则 return NULL,然后挑选出非具有 MAX()
(或 MIN()
聚合函数的 NULL 值。
然后我们可以使用 COALESCE
函数给我们第一个非 NULL 值,检查我们是否得到 score=3 行,然后是 score=2 行等。
SELECT p.person_id
, COALESCE(
MAX(CASE
WHEN p.person_default_name_id = n.name_id AND s.script_id = '1'
THEN n.name
ELSE NULL
END)
, MAX(CASE
WHEN n.language_id = '1'
THEN n.name
ELSE NULL
END)
, MAX(CASE
WHEN s.script_id = '1'
THEN n.name
ELSE NULL
END)
, MAX(n.name)
) AS `name`
-- additional expressions so we can see what is happening
, MAX(CASE
WHEN p.person_default_name_id = n.name_id AND s.script_id = '1'
THEN n.name
ELSE NULL
END) AS s3_name
, MAX(CASE
WHEN n.language_id = '1'
THEN n.name
ELSE NULL
END
) AS s2_name
, MAX(CASE
WHEN s.script_id = '1'
THEN n.name
ELSE NULL
END) AS s1_name
, MAX(n.name) AS s0_name
FROM `people` p
LEFT
JOIN `names` n
ON n.person_id = p.person_id
LEFT
JOIN `languages` l
ON l.language_id = n.language_id
LEFT
JOIN `language_scripts` s
ON s.language_id = l.language_id
GROUP
BY p.person_id
ORDER
BY ...
我整理了一个查询来提取人们的名字,优先考虑在查看页面的人的 language/writing 脚本中写入的那个名字的版本。
我之前遇到过遗漏记录的问题,post就此提出了一个问题 here. I received an answer 建议使用 CASE 语句并应用分数根据首选 language/script。我已经得到了排名,它允许返回正确数量的记录(现在没有丢失的记录)。见下文:
SELECT
people.person_id,
names.name,
CASE
WHEN people.person_default_name_id=names.name_id AND language_scripts.script_id = :user_script_id THEN 3
WHEN names.language_id = :user_language_id THEN 2
WHEN language_scripts.script_id = :user_script_id THEN 1
ELSE 0
END as score
FROM
`people`
LEFT JOIN
`names` ON names.person_id=people.person_id
LEFT JOIN
`languages` ON names.language_id = languages.language_id
LEFT JOIN
`language_scripts` ON languages.language_id = language_scripts.language_id
GROUP BY
people.person_id
ORDER BY
names.name ASC
我现在遇到的麻烦是,因为我只需要每个人一个结果(因此 GROUP BY),它只是拉出每个人遇到的第一条记录。我需要能够使 "score" 起作用,并且只提取具有最高可用分数(可能是 3、2、1 或 0)的记录——每个人的最高分数记录。
最初 post 中的建议是使用外部查询,但我不确定如何在此处应用它。有什么想法吗?
编辑:这个 fiddle 显示了一个示例,它提取了所有记录及其分数:http://sqlfiddle.com/#!9/54ce8/13 - 我想要做的是只提取每个 [= =27=]得分最高。在这个例子中,我想要一个 table 和 Jorge 和 Alejandro 只是因为他们是两个中得分最高的名字。
我只能想到一种方法来实现这一点。在您当前的工作查询中结合使用 GROUP_CONCAT
和 SUBSTRING_INDEX
。下面的示例查询:
SELECT person_id,
SUBSTRING_INDEX(GROUP_CONCAT(a.name ORDER BY a.score DESC),',',1) sname,
SUBSTRING_INDEX(GROUP_CONCAT(a.score ORDER BY a.score DESC),',',1) max_score FROM
(SELECT people.person_id,
names.name,
CASE
WHEN people.person_default_name_id=names.name_id AND language_scripts.script_id = '1' THEN 3
WHEN names.language_id = '1' THEN 2
WHEN language_scripts.script_id = '1' THEN 1
ELSE 0
END AS score
FROM `people`
LEFT JOIN `names` ON names.person_id=people.person_id
LEFT JOIN `languages` ON names.language_id = languages.language_id
LEFT JOIN `language_scripts` ON languages.language_id = language_scripts.language_id) a
GROUP BY person_id;
我也在 fiddle 中测试了查询 http://sqlfiddle.com/#!9/54ce8/33
一点解释:
GROUP_CONCAT
在名称和分数上添加ORDER BY
条件 - 请注意ORDER BY
在两个GROUP_CONCAT
.[=28= 中必须相同]SUBSTRING_INDEX
获取字段中以逗号 (,) 分隔的第一个值。
return score
重要吗?或者目标只是return一个满足score=3条件的name
,如果不存在,满足条件的return一个name
对于分数=2,否则...
一种方法是进行条件聚合,当满足条件时 return 值为 name
,否则 return NULL,然后挑选出非具有 MAX()
(或 MIN()
聚合函数的 NULL 值。
然后我们可以使用 COALESCE
函数给我们第一个非 NULL 值,检查我们是否得到 score=3 行,然后是 score=2 行等。
SELECT p.person_id
, COALESCE(
MAX(CASE
WHEN p.person_default_name_id = n.name_id AND s.script_id = '1'
THEN n.name
ELSE NULL
END)
, MAX(CASE
WHEN n.language_id = '1'
THEN n.name
ELSE NULL
END)
, MAX(CASE
WHEN s.script_id = '1'
THEN n.name
ELSE NULL
END)
, MAX(n.name)
) AS `name`
-- additional expressions so we can see what is happening
, MAX(CASE
WHEN p.person_default_name_id = n.name_id AND s.script_id = '1'
THEN n.name
ELSE NULL
END) AS s3_name
, MAX(CASE
WHEN n.language_id = '1'
THEN n.name
ELSE NULL
END
) AS s2_name
, MAX(CASE
WHEN s.script_id = '1'
THEN n.name
ELSE NULL
END) AS s1_name
, MAX(n.name) AS s0_name
FROM `people` p
LEFT
JOIN `names` n
ON n.person_id = p.person_id
LEFT
JOIN `languages` l
ON l.language_id = n.language_id
LEFT
JOIN `language_scripts` s
ON s.language_id = l.language_id
GROUP
BY p.person_id
ORDER
BY ...