在字段中选择按值分组

jjjwad0x  于 2021-06-24  发布在  Mysql
关注(0)|答案(5)|浏览(323)

给出以下(大大简化的)示例表:

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 ,有没有办法做到这一点?i、 因此我得到的结果是:

foo | read_write |
bar | read_only  |

我可能需要添加新的选项 access 列,但它们将始终按重要性顺序(从最低到最高)排列,因此,如果可能的话,一个能够处理此问题的解决方案将特别有用。
另外,要澄清的是,我的实际表中包含了除这些字段以外的其他字段,这就是为什么我不在表中使用唯一键的原因 name 列;按设计将有多行按名称排列,以满足各种标准。

pu3pd22g

pu3pd22g1#

您可以创建另一个优先级为 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)
ki0zmccv

ki0zmccv2#

gordon提出的解决方案足以满足当前的需求。
如果我们预期未来的优先级顺序要求不是按字母顺序的字符串顺序(或按枚举索引值)。。。
作为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 table拉着整排。。。

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' . 从另一个Angular 来看 name 只有一个 'read_only' 为了 access 查询不会返回。
对“值列表”(列表不“匹配”)的其他修改也可以实现更强大的规则。例如,我们可以排除 name 那和我有争执 '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' 行。
并不是说你有一个规范或当前的要求去做这些。对于将来有这些需求的查询,需要记住一些东西。

ktecyv1j

ktecyv1j3#

可以使用distinct语句(或group by)选择distinct名称,从选项卡访问;

35g0bw71

35g0bw714#

这同样有效:

SELECT name, MAX(access)
  FROM permissions
GROUP BY name ORDER BY MAX(access) desc
3bygqnnd

3bygqnnd5#

以下内容将对您的数据起作用:

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() 使用字符值。有些人甚至称之为虫子。

相关问题