使用 Microsoft Access SQL 将多值字段拆分为多条记录

问题描述 投票:0回答:1

我正在使用一个 Microsoft Access 表,该表以以下格式存储其数据:

身份证 文件 修订
8000C001 103A4000X001、103A4000X002、103A4000X003 A、B、A
8000C002 103A5000G002/1/01、/02、/03 C、D、B
8000C003 103A6000B001 A

我想使用 SQL Select 查询来重新格式化它,如下表所示:

身份证 文件 修订
8000C001 103A4000X001 A
8000C001 103A4000X002 B
8000C001 103A4000X003 A
8000C002 103A5000G002/1/01 C
8000C002 103A5000G002/1/02 D
8000C002 103A5000G002/1/03 B
8000C003 103A6000B001 A

文档之间用逗号分隔,但当文档具有相同前缀时,后续文件会缩写。

我设置了第二个表,其中包含每个文档的最新版本,并且当前正在使用外连接语句来重新格式化数据。

SELECT 
one.ID
two.Document, 
two.Revision, 
FROM [All Documents] AS one 
RIGHT JOIN [Active Documents] AS two 
ON (one.Document LIKE IIf(InStr(two.Document,"/")<>0, "*" & Left(two.Document,InStr(two.Document,"/")-1) & "*" & Right(two.Document,Len(two.Document)-InStr(two.Document,"/")) & "*", "*" & two.Document & "*")) 
AND (one.Revision LIKE "*" & two.Revision & "*");

这确实有效,但速度很慢。运行查询可能需要 20 多秒才能完成,因此我开始编写第二个脚本,使用 Unions 来格式化数据:

SELECT 
one.ID
one.Document, 
one.Revision
FROM 8110 AS one WHERE one.Document NOT like "*,*"
UNION
SELECT 
one.ID, 
Trim(Left(one.Document, InStr(one.Document, ",") - 1)), 
Left(one.Rev, 1)
FROM 8110 AS one WHERE one.Document LIKE "*,*"
UNION
SELECT 
one.ID, 
IIF(Left(Trim(Mid(one.Document, InStr(one.Document, ",") + 1)), 1) = "/", Left(one.Document, InStrRev(Trim(Left(one.Document,InStr(one.Document,",")-1)), "/")) & Trim(Mid(one.Document, InStr(one.Document, ",") + 3)), Trim(Mid(one.Document, InStr(one.Document, ",") + 1))), 
Trim(Mid(one.Revision, InStr(one.Revision, ",") + 1))
FROM 8110 AS one WHERE one.Document LIKE "*,*";

这比当前查询要快得多,但它仅适用于前两个文档。输出如下所示:

身份证 文件 修订
8000C001 103A4000X001 A
8000C001 103A4000X002、103A4000X003 B、A
8000C002 103A5000G002/1/01 C
8000C002 103A5000G002/1/02,/03 D、B
8000C003 103A6000B001 A

我可以通过添加额外的联合来解决这个问题,但我不知道一条记录可以包含多少个文档。 SQL 是否有某种形式的递归?在任何其他编程语言中,我只需使用逗号作为分隔符将文档转换为数组,然后为每个元素添加一条记录。

此外,我知道缩写文件使此查询变得非常复杂。您不必在回复中考虑到这一点;这是我要处理的问题。以下是我的查询的变体,它们不考虑缩写文件,只是用逗号分隔它们:

SELECT 
one.ID
two.Document, 
two.Revision, 
FROM [All Documents] AS one 
RIGHT JOIN [Active Documents] AS two 
ON (one.Document LIKE "*" & two.Document & "*")) 
AND (one.Revision LIKE "*" & two.Revision & "*");
SELECT 
one.ID
one.Document, 
one.Revision
FROM 8110 AS one WHERE one.Document NOT like "*,*"
UNION
SELECT 
one.ID, 
Trim(Left(one.Document, InStr(one.Document, ",") - 1)), 
Left(one.Rev, 1)
FROM 8110 AS one WHERE one.Document LIKE "*,*"
UNION
SELECT 
one.ID, 
Trim(Mid(one.Document, InStr(one.Document, ",") + 1)),
Trim(Mid(one.Revision, InStr(one.Revision, ",") + 1))
FROM 8110 AS one WHERE one.Document LIKE "*,*";
sql ms-access
1个回答
0
投票

也许您可以尝试使用辅助表和 VBA 函数:

  1. 创建一个新表,序号为0,1,2,3(整数列Seq ): tblSeq,max 是您期望的最大零件数,
  2. 创建一个 VBA 函数来提取字符串的子部分(给定其位置):
Public Function GetSubString(Str As String, Seq As Integer) As String
   Dim strRetVal As String, CommaPos As Integer, i As Integer, CommaPosNext As Integer
   strRetVal = ""
   CommaPos = 0
   For i = 1 To Seq
       CommaPos = InStr(CommaPos + 1, Str, ",")
   Next i
   CommaPosNext = InStr(CommaPos + 1, Str, ",")
   GetSubString = Mid(Str, CommaPos + 1, IIf(CommaPosNext = 0, 255, CommaPosNext - CommaPos - 1))
   
End Function

那么你的查询可能是这样的:

SELECT TBL.ID, TBL.Document, TBL.Revision, Seq.Seq, GetSubString(TBL.Revision,Seq.Seq) as Rev
from YourTbl as TBL,
     tblSeq Seq
where len(TBL.Revision)-len(replace(TBL.Revision,',',''))>=Seq.Seq

并不声称它会比任何其他选项表现更好。

© www.soinside.com 2019 - 2024. All rights reserved.