MySQL选择默认是最后的手段

Posted

技术标签:

【中文标题】MySQL选择默认是最后的手段【英文标题】:MySQL Select where default is last resort 【发布时间】:2021-09-01 06:08:05 【问题描述】:

我正在尝试获取一个连接表,同时按一列排序并分组。我正在尝试选择以 CU 开头的 CUID,而不是 DEFAULT 值。我已经阅读了 *** 上发布的答案,看来我做的事情是正确的。我认为这可能只是我缺少的一些小东西。我认为由于插入顺序,order by 不起作用。我想进行查询以使用 DEFAULT 作为其最后一个选项。

SELECT A.*, B.value, B.CUID  
FROM A 
JOIN B 
ON A.ID = B.SettingID 
WHERE B.CUID = 'CU1' OR B.CUID = 'DEFAULT'
GROUP BY ID
ORDER BY CUID ASC 

在朋友的帮助下,发现由于插入顺序和 B.CUID 按字母顺序排列在“DEFAULT”之后,这仅在某些时候有效。

表 A

| id   | Name  | 
|  1   |  blah |
|  2   |  was  | 
|  3   |  here | 

表 B

| ID   | SettingID | Value | CUID    |
|  1   |  1        |  a    | CU1     |
|  2   |  2        |  b    | CU1     |
|  3   |  1        |  c    | DEFAULT |
|  4   |  2        |  d    | DEFAULT |
|  5   |  3        |  e    | DEFAULT |

没有 GROUP BY 的结果

|  SettingID | Name | Value | CUID    |
|    1       | blah |  a    | CU1     |
|    2       | was  |  b    | CU1     |
|    1       | blah |  c    | DEFAULT |
|    2       | was  |  d    | DEFAULT |
|    3       | here |  e    | DEFAULT |

GROUP BY 后的结果

|  SettingID | Name | Value | CUID    |
|    1       | blah |  c    | DEFAULT |
|    2       | was  |  d    | DEFAULT |
|    3       | here |  e    | DEFAULT |

预期结果

|  SettingID | Name | Value | CUID    |
|    1       | blah |  a    | CU1     |
|    2       | was  |  b    | CU1     |
|    3       | here |  e    | DEFAULT |

【问题讨论】:

查询不正确。请参阅 ONLY_FULL_GROUP_BY sql 模式说明。 @Akina 这个查询对我来说很好。 查询对我来说很好用。“很好用”和“给出意外结果”不兼容。关于查询。您的数据中有 Value'a''c' 对应于 SettingID=1。分组后服务器必须返回一个值。您尚未指定必须返回的内容(first-last-greatest-least-etc.)。服务器从他们那里随机返回一个 - 这对它来说是正确的。没有明确描述的任何东西都可以是任何东西。你需要一些确定的价值吗?如果是这样,那么您的查询不符合您的需要 - 即它不正确。 @akina 抱歉,我更新了我的问题,使其更具体。该表可以有一个 DEFAULT 设置和任何其他 CUID 设置。只会有另一个。存在 DEFAULT 且 CUID = BLAH 时的示例。我想用 BLAH 抢排。我希望 DEFAULT 成为次要选项。 【参考方案1】:

您可以使用EXISTS 执行此操作,这样对于每个SettingID,您将获得以CUID 开头的行,以'CU' 开头,或者如果它不存在,那么您将获得具有替代值的行:

SELECT a.*, b.value, b.CUID 
FROM TableA a 
INNER JOIN (
  SELECT b1.*
  FROM TableB b1
  WHERE b1.CUID LIKE 'CU%'
     OR NOT EXISTS (
       SELECT 1
       FROM TableB b2
       WHERE b2.SettingID = b1.SettingID AND b2.CUID LIKE 'CU%'
     )
) b ON b.SettingID = a.id

如果你的mysql版本是8.0+,你可以使用TableB表中的ROW_NUMBER()窗口函数来获取首选行:

SELECT a.*, b.value, b.CUID 
FROM TableA a 
INNER JOIN (
  SELECT *, ROW_NUMBER() OVER (PARTITION BY SettingID ORDER BY CUID LIKE 'CU%' DESC) rn
  FROM TableB
) b ON b.SettingID = a.id
WHERE b.rn = 1

请参阅demo。

【讨论】:

这正是我想要的。我需要做的就是将“CU%”更改为我正在寻找的实际值。谢谢。【参考方案2】:

该表可以有一个 DEFAULT 设置和任何其他 CUID 设置。只会有另一个。

我会使用

SELECT b1.SettingID, 
       a.name,
       COALESCE(b2.value, b1.value) AS value,
       COALESCE(b2.CUID, b1.CUID) AS CUID
FROM a
JOIN b AS b1 on a.id = b1.SettingID
LEFT JOIN b AS b2 ON a.id = b2.SettingID 
                 AND b2.CUID != 'DEFAULT'
WHERE b1.CUID = 'DEFAULT'  

如果每个SettingID 可能有多个'DEFAULT',则添加DISTINCT

【讨论】:

这并没有给我任何默认值。结果只是设置ID 1和2 @SariRahal 哎呀……对不起。固定。

以上是关于MySQL选择默认是最后的手段的主要内容,如果未能解决你的问题,请参考以下文章

MySQL安装及配置

如何使用 MySQL 选择最后一行匹配条件的父/子关系的最后一个子行

MySQL - 选择最后插入的行最简单的方法

从 MySQL 中选择最后 N 行

从 MySQL 中选择最后 N 行

linux安装MySQL启动报错