给出以下(大大简化)的示例表:
CREATE TABLE `permissions` (
`name` varchar(64) NOT NULL DEFAULT '',
`access` enum('read_only','read_write') NOT NULL DEFAULT 'read_only'
);
以下示例内容:
| name | access |
=====================
| foo | read_only |
| foo | read_write |
| bar | read_only |
我想要做的是运行SELECT
查询,为name
中的每个唯一值抓取一行,支持access
值为read_write
的那些,是有办法可以做到这一点吗?因此,我得到的结果是:
foo | read_write |
bar | read_only |
我可能需要在将来向access
列添加新选项,但它们将始终按重要性顺序排列(从最低到最高),因此,如果可能的话,可以应对此问题的解决方案尤其如此是有用的。
另外,为了澄清,我的实际表格包含除这些之外的其他字段,这就是我没有在name
列上使用唯一键的原因;按设计名称将有多行符合各种标准。
答案 0 :(得分:3)
以下内容适用于您的数据:
select name, max(access)
from permissions
group by name;
但是,这按字符串值排序,而不是索引。这是另一种方法:
select name,
substring_index(group_concat(access order by access desc), ',') as access
from permissions
group by name;
order by
按索引排序但min()
和max()
使用字符值相当时髦。有些人甚至可能称这是一个错误。
答案 1 :(得分:2)
您可以创建另一个优先级为access
的表(这样您可以添加新选项),然后分组并找到优先级表的MIN()
值:
E.g。创建一个名为Priority
的表,其值为
| PriorityID| access |
========================
| 1 | read_write |
| 2 | read_only |
然后,
SELECT A.Name, B.Access
FROM (
SELECT A.name, MIN(B.PriorityID) AS Most_Valued_Option -- This will be 1 if there is a read_write for that name
FROM permissions A
INNER JOIN Priority B
ON A.Access = B.Access
GROUP BY A.Name ) A
INNER JOIN Priority B
ON A.Most_Valued_Option = B.PriorityID
-- Join that ID with the actual access
-- (and we will select the value of the access in the select statement)
答案 2 :(得分:1)
戈登提出的解决方案足以满足当前的要求。
如果我们预计未来要求优先顺序不是按字母顺序排列(或通过枚举索引值)...
作为Gordon答案的修改版本,我很想使用MySQL FIELD
函数和(它的逆向)ELT
函数,如下所示:
SELECT p.name
, ELT(
MIN(
FIELD(p.access
,'read_only','read_write','read_some'
)
)
,'read_only','read_write','read_some'
) AS access
FROM `permissions` p
GROUP BY p.name
如果规范要提取整行,而不仅仅是access
列的值,我们可以使用内联视图查询来查找首选access
,并将连接返回到preferences
表来拉整行...
SELECT p.*
FROM ( -- inline view, to get the highest priority value of access
SELECT r.name
, MIN(FIELD(r.access,'read_only','read_write','read_some')) AS ax
FROM `permissions` r
GROUP BY r.name
) q
JOIN `permissions` p
ON p.name = q.name
AND p.access = ELT(q.ax,'read_only','read_write','read_some')
请注意,此查询不仅返回具有最高优先级的access
,还可以返回该行中的任何列。
使用FIELD
和ELT
函数,我们可以实现特定已知值列表的任何临时排序。不仅仅是字母顺序,还是按枚举索引值排序。
“priority”的逻辑可以包含在查询中,并且不依赖于permissions
表中的额外列或任何其他表的内容。
要获取我们正在寻找的行为,只需指定access
的优先级,FIELD
函数中使用的“值列表”将需要匹配“值列表” ELT
函数的顺序相同,列表应包含access
的所有可能值。
参考:
http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_elt
http://dev.mysql.com/doc/refman/5.7/en/string-functions.html#function_field
高级用法
并非您有要求这样做,但考虑到未来可能的要求......我们注意到......
“值列表”的不同顺序将导致access
的优先级顺序不同。因此,各种查询都可以为“优先级”实现自己的不同规则。通过重新排序完整的“值列表”,查找第一个,第二个等access
值。
除了重新排序之外,还可以从FIELD
和ELT
函数中的“值列表”中省略一个可能的值。例如,考虑从此行的列表中省略'read_only'
值:
, MIN(FIELD(r.access,'read_write','read_some')) AS ax
并从这一行:
AND p.access = ELT(q.ax,'read_write','read_some')
这将有效地限制返回的name
行。仅name
access
值为'read_write'
或'read_some'
的{{1}}。另一种查看方式,name
只有 'read_only'
access
name
将{em>
对“值列表”的其他修改也是可能的,其中列表不“匹配”,以实现更强大的规则。例如,我们可以排除有'read_only'
行的ELT
。
例如,在'read_only'
函数中,我们使用一个我们知道在任何行上都不存在(也不能存在)的值来代替'read_only'
值。为了说明,
我们可以将 , MIN(FIELD(r.access,'read_only','read_write','read_some')) AS ax
^^^^^^^^^^^
列为此行的“最高优先级”......
'read_only'
所以如果找到ELT
的行,那将优先考虑。但是在外部查询的 AND p.access = ELT(q.ax,'eXcluDe','read_write','read_some')
^^^^^^^^^
函数中,我们可以将其转换回不同的值......
'eXcluDe'
如果我们知道access
列中不存在name
,我们就会有效地排除任何'read_only'
行'read_write'
,即使有import itertools
list(itertools.chain(*[[str(s),'Numpad{}'.format(s)] for s in range(1,10)]))
行list(itertools.chain.from_iterable([str(s),'Numpad{}'.format(s)] for s in range(0,10)))
行。
并非您有规范或当前要求执行任何此操作。对于具有这些要求的未来查询,请记住一些事项。
答案 3 :(得分:0)
您可以使用不同的声明(或分组依据) 选择不同的名称,访问 FROM标签;
答案 4 :(得分:0)
这也有效:
SELECT name, MAX(access)
FROM permissions
GROUP BY name ORDER BY MAX(access) desc