SQL 更新语句为每个不同的表记录子集填充数字系列
Posted
技术标签:
【中文标题】SQL 更新语句为每个不同的表记录子集填充数字系列【英文标题】:SQL update statement to populate numerical series for each distinct subset of table records 【发布时间】:2014-03-25 17:40:37 【问题描述】:我需要 SQL 更新语句将连续的序列号分配给表中的记录子集。我正在使用 MS 访问权限。
假设当前表有如下记录:
notebook,blue
notebook.Yellow
pencil,yellow
chair,blue
desk,green
desk,blue
我想在表格中添加另一个字段并按如下方式填充它:
notebook,blue,1
notebook.Yellow,1
pencil,yellow,2
chair,blue,2
desk,green,1
desk,blue,3
你看到我已经根据一组标准给出了一个连续的数字分配。在此示例中,条件是第二个字段中的不同值(在现实生活中,条件将是来自多个字段的值的不同组合,但所有相关字段都在同一个表中......不需要连接获取标准)。由于字段 2 中有三个蓝色记录,因此编号为 1、2、3。并且由于有两条记录为黄色,它们的编号为 1,2。
所以我不能从行号推导出编号,因为我在同一张表中有几个编号系列都从 1 开始。
另外,我需要它是一个不需要在第二个字段中明确指定值的查询。我只希望第二个字段中的每个唯一值都有自己的编号序列。也就是说,我不想显式编写一个查询来生成“蓝色”的数字,并编写一个单独的查询来生成“黄色”的数字
系列中的最大记录数低于 1000。所以我不介意是否需要创建一个包含 1000 条记录的辅助表,其中一个字段包含值 1 到 1000。然后更新语句到主表可以从辅助表中提取下一个值。
但我不知道用于此更新语句或任何其他方法的更新语句的 SQL 语法。所以我需要你的建议。
【问题讨论】:
【参考方案1】:我不确定如何使用单个 SQL 语句来执行此操作,但这里有 2 个 SQL 语句可用于处理每种情况:
insert into table ('desk', 'blue', 1)
where not exists (select field3 from table where field1 = 'desk' and field2 = 'blue');
insert into table (field1, field2, field3)
select field1, field2, count(1) + 1
from table
where field1 = 'desk'
and field2 = 'blue'
group by field1, field2;
【讨论】:
我不介意需要使用多个 SQL 语句,并且我没有测试您提供的语句,因为语法不适合 MS 访问。但我认为这种方法行不通,因为我不想在查询中指定特定值(例如“蓝色”)。在现实生活中,我有太多的潜在价值需要管理,未来可能会听到新的价值,所以我希望查询能够动态发现“颜色”,并为所有具有某种颜色的项目赋予自己的数字序列。跨度> 您将使用您用来填充数据库的任何代码插入特定值(例如:“蓝色”)。我在这里硬编码这些值只是作为一个例子。【参考方案2】: Create Table #TableAutoIncrement (ID int identity(1000 , 1) , item varchar(20), COLOR varchar(20) )
Insert INTO #TableAutoIncrement
(item, COLOR )
SELECT item, COLOR FROM YOURTABLE
--- 获取临时表中的所有值
SELECT * FROM #TableAutoIncrement
【讨论】:
语法在 MS 访问中不起作用,但在我弄清楚如何修改语法之前,我想看看通用方法是否能解决我的问题。如果我正确理解这是如何工作的,那么它不会解决问题。看起来我正在为我的真实数据表创建一个并行表,其中包含一个额外的自动递增字段,编号为 1 到 1000。然后我将主表中的所有记录插入到这个自动编号的表中,以提供我的每个主表记录一个数字。 限制是这将在整个表格中按顺序编号项目。我需要多个记录子集彼此拥有从1开始的编号顺序。也就是说,第一个蓝色记录是1,但第一个黄色记录也是1。我相信这种方法会将第一个记录分配为1(不管的颜色),第二条记录为 2,无论颜色如何,等等。【参考方案3】:我的一位同事制定了必要的 SQL。这是通用解决方案(请注意,我确实需要根据两个字段的组合对数据集中的多个系列进行编号。在原始帖子中的简化示例中,我只使用了一个字段 - 颜色 - 但因为我确实需要两个字段,这就是我在这个解决方案中展示的内容。
SELECT *,
(SELECT COUNT(T1.ID)
FROM
[TableName] AS T1
WHERE T1.ID >= T2.ID and t1.[NameCriteriaField1] = t2.[NameCriteriaField1]
and t1.[NameCriteriaField2]= t2.[NameCriteriaField2])
AS Sequence into OutputResultsTableName
FROM
[TableName] AS T2
ORDER BY [NameCriteriaField2] , [NameCriteriaField1]
源表设置为“ID”作为具有整数值的字段。每条记录都有一个唯一的 ID 值,但 ID 中是否存在间隙或记录如何根据 ID 排序都无关紧要。 (例如,典型的 MS 访问自动编号的主键字段用于此目的)
此查询设置为假设您的数据集中有两个字段要用于对记录进行分组,并为每个组中的每个记录分配一个数字系列计数。 (因此您的表可能包含多个组,并且每个组都有自己的编号序列,从 1 开始。但查询的制定方式,正好有 2 个标准来定义组。)您不能使用任何 where 子句来进一步过滤被计数的记录。通过实验,我发现添加 where 子句会产生不可靠的结果,其中记录可能会被省略。因此,如果您需要过滤结果以使某些记录不包含在特定组的数字系列中,请在运行我的查询之前执行以下操作之一:
运行查询以从源表中删除不需要的记录
首先将源表中的所有记录复制到新表中,并删除新表中不应该编号的记录,然后在新表上运行我的查询
仅当这些记录符合条件 1 和条件 2 定义的组的成员时才需要在运行此查询之前删除无关记录。如果存在与这两个条件不匹配的无关记录,您可以离开它们在表中,因为它们不会影响您关心的组中记录的编号。他们只会获得自己的独立编号,您可以忽略它。**
每个组的编号从 1 开始,查询根据条件 1 和条件 2 的不同组合动态定义组。但是,如果您有不属于任何组的记录,则这些记录将全部编号为 0。(Criteria1 和 criteria2——至少在我的测试范围内——是非空值。(理论上——至少在 Microsoft Access 上,空字符串与 Null 不同,但我也没有使用空字符串对此进行测试。)如果您的记录在条件 1 或条件 2 字段中为空,MS Access 会将这些记录视为不属于任何组,因此将它们编号为 0。也就是说,这些不同的组需要为条件 1 和条件 2 定义非空值,因此这与 SQL DISTINCT 语句的工作方式不同。
如果您需要将 NULL 作为定义组的有效标准(从而使组由 NULL 编号),这非常简单。在运行我的查询之前,首先运行一条更新语句,将条件 1 或条件 2 中的所有空值实例更改为短语“空字段的占位符”。然后运行我的查询。在结果集上(在为组分配编号之后),运行另一个更新以将所有出现的占位符短语改回 null。
如果您的组仅由一个字段标准定义,则调整语法
SELECT *,
(SELECT COUNT(T1.ID)
FROM
[TableName] AS T1
WHERE T1.ID >= T2.ID and t1.[NameCriteriaField1] = t2.[NameCriteriaField1] )
AS Sequence into OutputResultsTableName
FROM
[TableName] AS T2
ORDER BY [NameCriteriaField2] , [NameCriteriaField1]
如果您的组由 3 个字段条件的组合定义,则调整语法
SELECT *,
(SELECT COUNT(T1.ID)
FROM
[TableName] AS T1
WHERE T1.ID >= T2.ID and t1.[NameCriteriaField1] = t2.[NameCriteriaField1]
and t1.[NameCriteriaField2]= t2.[NameCriteriaField2]
and t1.[NameCriteriaField3]= t2.[NameCriteriaField3])
AS Sequence into OutputResultsTableName
FROM
[TableName] AS T2
ORDER BY [NameCriteriaField2] , [NameCriteriaField1]
【讨论】:
以上是关于SQL 更新语句为每个不同的表记录子集填充数字系列的主要内容,如果未能解决你的问题,请参考以下文章