SQL - 手动获取给定格式的下一个可用 ID
Posted
技术标签:
【中文标题】SQL - 手动获取给定格式的下一个可用 ID【英文标题】:SQL - Manually obtain the next available ID for the given format 【发布时间】:2021-11-23 23:05:03 【问题描述】:我正在尝试构建一个简单的 SQL SELECT 语句,该语句手动提供可用于给定格式的下一个唯一 ID。
例如,请看下表。
-- Students (Table)
-- ID - Not a primary key
-- Type - Numbering format
+----------+------+
| ID | Type |
+----------+------+
| 1 | M |
| 2 | M |
| 5 | M |
| 7056 | F |
| 7057 | F |
| 7058 | F |
| 7090 | F |
| 7091 | N |
| 10910 | N |
| 10911 | N |
| 99000000 | O |
| 99000001 | O |
+----------+------+
-- Some of the available values:
+---+------+-------+----------+
| M | F | N | O |
+---+------+-------+----------+
| 6 | 7092 | 10912 | 99000002 |
| 7 | 7093 | 10913 | 99000003 |
| 8 | 7094 | 10914 | 99000004 |
+---+------+-------+----------+
在这里,假设我想将类型“F”的“7092”作为下一个值。但是如果我使用 MAX 函数,它会返回 '99000002'。
SELECT MAX(id)+1 FROM students;
如果我使用类型列,我可以获得类型“F”的“7091”,但这不可用,因为它被另一种类型使用。
SELECT MAX(id)+1 FROM students WHERE type = 'F';
这也行不通。
SELECT MAX(id)+1
FROM students
WHERE type = 'F'
AND id NOT IN ( SELECT DISTINCT id FROM students)
我无法更改数据库结构。如果是这样,对于给定的场景,是否有办法(单个 SELECT 语句)获取所选类型的下一个可用 ID(例如:F 型)? 我用的是Oracle 10g,但是mysql和SQL Server也可以。
CREATE TABLE students (
id NUMBER,
type CHAR(1)
);
INSERT INTO students VALUES (1, 'M');
INSERT INTO students VALUES (2, 'M');
INSERT INTO students VALUES (5, 'M');
INSERT INTO students VALUES (7056, 'F');
INSERT INTO students VALUES (7057, 'F');
INSERT INTO students VALUES (7058, 'F');
INSERT INTO students VALUES (7090, 'F');
INSERT INTO students VALUES (7091, 'N');
INSERT INTO students VALUES (10910, 'N');
INSERT INTO students VALUES (10911, 'N');
INSERT INTO students VALUES (99000000, 'O');
INSERT INTO students VALUES (99000001, 'O');
如果能提供任何帮助,我将不胜感激。无论如何,感谢您的宝贵时间。
【问题讨论】:
我没有看到连续 id 的意义。主键列的唯一重要方面是它必须是唯一的。没有人真正关注或关心它所具有的特定价值。只要它唯一地标识一行,一切都很好。 我不明白 - 为什么 7 是下一个可用值,而不是 3? (除了更大的问题:这个练习在现实生活中的应用是什么?)另外,“类型”与这个问题有什么关系?您为什么要查看 type = M 的 id 以尝试解决您的问题?这没有任何意义 - 请更好地解释。还有一个问题——text
是什么数据类型?
你为什么要重新发明***,只使用标识列
如果您无法更改数据库以适应要求,请与管理层讨论他们为什么要束缚您的手脚。为工作使用正确的工具。 MAX(id)
等技巧存在重大的并发性和可管理性问题
@Charlieface,不幸的是,不,不。这是一个有许多值的旧表,它也与其他表和程序链接。所以,这并不容易。我只是想让我的任务更容易。我也很好奇。就是这样。
【参考方案1】:
你可以使用:
SELECT COALESCE(MAX(id) + 1,1) AS next_id
FROM (
SELECT id,
ROW_NUMBER() OVER (ORDER BY id) AS rn
FROM students
)
WHERE id = rn;
或:
SELECT COALESCE(MAX(id + 1), 1) AS next_id
FROM students
WHERE CONNECT_BY_ISLEAF = 1
START WITH id = 1
CONNECT BY PRIOR id + 1 = id;
对于您的示例数据,两个输出:
NEXT_ID 3
注意:如果第一个 id
值被删除,这些查询都将返回 1
。
但是,更好的解决方案是使用序列并让其处理生成键,而不必担心值之间的间隙。
db小提琴here
【讨论】:
【参考方案2】:您正在寻找差距,因此您正在寻找 id 列表中的值 NOT IN
。
以下查询将为您提供所有 id 的 NOT IN
表的列表。
SELECT sub_id FROM (
SELECT id+1 as sub_id FROM students
)sub_table WHERE sub_id NOT IN (
SELECT id FROM students
);
然后您可以选择该列表的MIN()
:
SELECT MIN(sub_id) FROM (
SELECT id+1 as sub_id FROM students
)sub_table WHERE sub_id NOT IN (
SELECT id FROM students
);
请记住,这仅在您已经拥有至少一个 id 时才有效,并且除非您已经拥有 id 1,否则它不会从 1 开始。
注意:第一个查询只为您提供所有间隙的列表以及下一个可用的 id。
【讨论】:
以上是关于SQL - 手动获取给定格式的下一个可用 ID的主要内容,如果未能解决你的问题,请参考以下文章
我必须对 SQL 中的给定结果使用 80/20。有一些可用的资源,但我仍然无法离题[重复]
如何在 Directwrite 中为给定字体获取可用的 OpenType 功能?