我正在使用一个 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 "*,*";
也许您可以尝试使用辅助表和 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
并不声称它会比任何其他选项表现更好。