SQL 根据 1 个或多个可能的分隔符拆分列并插入新的 table
SQL Split column based on 1 or more possible delimiter and insert in new table
我目前正在 MS-Access 2010 中开发 SQl,它可以根据分隔符 (,) 拆分列。在我要拆分的列中可以有零、一、二或三个分隔符。我发现如果只有一个定界符(请参阅问题末尾的 SQL)但如果有多个定界符则不能拆分列。
SQL是基于下面的table。 table 填充了 table.
中可能出现的数据
ID column_value
---------------------
1 2, 44
2 1
3 8, 9, 4
4 7
我想以这样的方式拆分列 "value",从而创建一个新的 table。 "ID"列相同不是问题,因为这不会是PK。
ID value
---------------------
1 2
1 44
2 1
3 8
3 9
3 4
4 7
我试图从 this question 更改 SQL 但它只在只有 1 个定界符 (,) 时有效,因为事实上它使用了函数 LEFT 和 MID。如果列中有超过 1 个定界符,我无法找到如何以可以拆分的方式更改它。如果有一个分隔符,我用来分割的SQL:
select * into importeddata
from (SELECT column_value, id
FROM SourceData
WHERE InStr(column_value, ',') = 1
UNION ALL
SELECT Left(column_value, InStr(column_value, ',') - 1), id
FROM SourceData
WHERE InStr(column_value, ',') > 0
UNION ALL
SELECT mid(column_value, InStr(column_value, ',')+1 ), id
FROM SourceData
WHERE InStr(column_value, ',') > 0) AS CleanedUp;
有人知道如果有一个以上的分隔符如何拆分一列吗?
要拆分并获取特定值,我更喜欢使用用户自定义函数。
Public Function SplitString(str As String, delimiter As String, count As Integer) As String
Dim strArr() As String
strArr = Split(str, delimiter, count + 1)
count = count - 1 'zero-based
If UBound(strArr) >= count Then
SplitString = strArr(count)
End If
End Function
在此之后,您可以将 SQL 调整为以下内容:
SELECT * INTO importeddata
FROM (
SELECT SplitString(column_value, ',', 1), id
FROM SourceData
WHERE SplitString(column_value, ',', 1) <> ''
UNION ALL
SELECT SplitString(column_value, ',', 2), id
FROM SourceData
WHERE SplitString(column_value, ',', 2) <> ''
UNION ALL
SELECT SplitString(column_value, ',', 3), id
FROM SourceData
WHERE SplitString(column_value, ',', 3) <> ''
) AS A
如果您真的想要一个全 SQL 解决方案,让我向您演示如何实现,以及为什么这是一个糟糕的计划。
对于这个例子,我编写了以下代码来自动生成适当的 SQL 表达式
Public Sub GenerateSQLSplit(str As String, Delimiter As String, Count As Integer)
Dim i As Integer
If Count = 1 Then
Debug.Print "IIf(InStr(1, " & str & ", " & Delimiter & ") = -1, " & str & ", Left(" & str & ", InStr(1, " & str & ", " & Delimiter & ") - 1))"
Else
Dim strPrevious As String
Dim strNext As String
strPrevious = "InStr(1, " & str & "," & Delimiter & ")"
i = Count - 1
Do While i <> 1
strPrevious = "InStr(" & strPrevious & " + Len(" & Delimiter & "), " & str & "," & Delimiter & ")"
i = i - 1
Loop
strNext = "InStr(" & strPrevious & " + Len(" & Delimiter & "), " & str & " , " & Delimiter & ")"
Debug.Print "IIf( " & strPrevious & "> 0, IIf(" & strNext & " < 1, Mid(" & str & ", " & strPrevious & " + Len(" & Delimiter & ")), Mid(" & str & ", " & strPrevious & " + Len(" & Delimiter & "), " & strNext & " - " & strPrevious & " - Len(" & Delimiter & "))), """") "
End If
End Sub
让我们使用示例来生成一个简单的拆分:我想要以下字符串的第 6 个元素:1,2,3,4,5,6,7
要生成字符串,在立即window:
GenerateSQLSplit "'1,2,3,4,5,6,7'", "','", 6
结果为 return 该字符串的第 6 个元素(仅限 SQL)的以下表达式:
IIf( InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',')> 0, IIf(InStr(InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7' , ',') < 1, Mid('1,2,3,4,5,6,7', InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(',')), Mid('1,2,3,4,5,6,7', InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), InStr(InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7'
,',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7' , ',') - InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') - Len(','))), "")
将 SELECT
附加到它的开头,并将其作为查询执行,并且它 returns 6
,正如预期的那样。只有你有一个完全可怕的查询,而使用 UDF 你只会有 SELECT SplitString("1,2,3,4,5,6,7", ",", 6)
当然,您可以使用 GenerateSQLSplit
创建查询(如果项目不在字符串中,我确保它 returned 一个空字符串,因此您可以使用它来测试第 n 个元素是否存在)。不过,我不推荐这样做,因为查询会很长、效率低下且难以维护。
我目前正在 MS-Access 2010 中开发 SQl,它可以根据分隔符 (,) 拆分列。在我要拆分的列中可以有零、一、二或三个分隔符。我发现如果只有一个定界符(请参阅问题末尾的 SQL)但如果有多个定界符则不能拆分列。
SQL是基于下面的table。 table 填充了 table.
中可能出现的数据ID column_value
---------------------
1 2, 44
2 1
3 8, 9, 4
4 7
我想以这样的方式拆分列 "value",从而创建一个新的 table。 "ID"列相同不是问题,因为这不会是PK。
ID value
---------------------
1 2
1 44
2 1
3 8
3 9
3 4
4 7
我试图从 this question 更改 SQL 但它只在只有 1 个定界符 (,) 时有效,因为事实上它使用了函数 LEFT 和 MID。如果列中有超过 1 个定界符,我无法找到如何以可以拆分的方式更改它。如果有一个分隔符,我用来分割的SQL:
select * into importeddata
from (SELECT column_value, id
FROM SourceData
WHERE InStr(column_value, ',') = 1
UNION ALL
SELECT Left(column_value, InStr(column_value, ',') - 1), id
FROM SourceData
WHERE InStr(column_value, ',') > 0
UNION ALL
SELECT mid(column_value, InStr(column_value, ',')+1 ), id
FROM SourceData
WHERE InStr(column_value, ',') > 0) AS CleanedUp;
有人知道如果有一个以上的分隔符如何拆分一列吗?
要拆分并获取特定值,我更喜欢使用用户自定义函数。
Public Function SplitString(str As String, delimiter As String, count As Integer) As String
Dim strArr() As String
strArr = Split(str, delimiter, count + 1)
count = count - 1 'zero-based
If UBound(strArr) >= count Then
SplitString = strArr(count)
End If
End Function
在此之后,您可以将 SQL 调整为以下内容:
SELECT * INTO importeddata
FROM (
SELECT SplitString(column_value, ',', 1), id
FROM SourceData
WHERE SplitString(column_value, ',', 1) <> ''
UNION ALL
SELECT SplitString(column_value, ',', 2), id
FROM SourceData
WHERE SplitString(column_value, ',', 2) <> ''
UNION ALL
SELECT SplitString(column_value, ',', 3), id
FROM SourceData
WHERE SplitString(column_value, ',', 3) <> ''
) AS A
如果您真的想要一个全 SQL 解决方案,让我向您演示如何实现,以及为什么这是一个糟糕的计划。
对于这个例子,我编写了以下代码来自动生成适当的 SQL 表达式
Public Sub GenerateSQLSplit(str As String, Delimiter As String, Count As Integer)
Dim i As Integer
If Count = 1 Then
Debug.Print "IIf(InStr(1, " & str & ", " & Delimiter & ") = -1, " & str & ", Left(" & str & ", InStr(1, " & str & ", " & Delimiter & ") - 1))"
Else
Dim strPrevious As String
Dim strNext As String
strPrevious = "InStr(1, " & str & "," & Delimiter & ")"
i = Count - 1
Do While i <> 1
strPrevious = "InStr(" & strPrevious & " + Len(" & Delimiter & "), " & str & "," & Delimiter & ")"
i = i - 1
Loop
strNext = "InStr(" & strPrevious & " + Len(" & Delimiter & "), " & str & " , " & Delimiter & ")"
Debug.Print "IIf( " & strPrevious & "> 0, IIf(" & strNext & " < 1, Mid(" & str & ", " & strPrevious & " + Len(" & Delimiter & ")), Mid(" & str & ", " & strPrevious & " + Len(" & Delimiter & "), " & strNext & " - " & strPrevious & " - Len(" & Delimiter & "))), """") "
End If
End Sub
让我们使用示例来生成一个简单的拆分:我想要以下字符串的第 6 个元素:1,2,3,4,5,6,7
要生成字符串,在立即window:
GenerateSQLSplit "'1,2,3,4,5,6,7'", "','", 6
结果为 return 该字符串的第 6 个元素(仅限 SQL)的以下表达式:
IIf( InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',')> 0, IIf(InStr(InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7' , ',') < 1, Mid('1,2,3,4,5,6,7', InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(',')), Mid('1,2,3,4,5,6,7', InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), InStr(InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7'
,',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7' , ',') - InStr(InStr(InStr(InStr(InStr(1, '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') + Len(','), '1,2,3,4,5,6,7',',') - Len(','))), "")
将 SELECT
附加到它的开头,并将其作为查询执行,并且它 returns 6
,正如预期的那样。只有你有一个完全可怕的查询,而使用 UDF 你只会有 SELECT SplitString("1,2,3,4,5,6,7", ",", 6)
当然,您可以使用 GenerateSQLSplit
创建查询(如果项目不在字符串中,我确保它 returned 一个空字符串,因此您可以使用它来测试第 n 个元素是否存在)。不过,我不推荐这样做,因为查询会很长、效率低下且难以维护。