【问题标题】:SQL Split column based on 1 or more possible delimiter and insert in new table基于 1 个或多个可能的分隔符的 SQL 拆分列并插入新表
【发布时间】:2018-04-11 08:38:20
【问题描述】:

我目前正在研究 MS-Access 2010 中的 SQl,它可以基于分隔符 (,) 拆分列。在我要拆分的列中可以有零、一、二或三分隔符。我发现如果只有一个分隔符(请参阅问题末尾的 SQL),但如果有多个分隔符,我可以拆分列。

SQL 基于下表。该表中填满了表中可能出现的数据。

ID         column_value
---------------------
1          2, 44
2          1
3          8, 9, 4
4          7

我想以创建这样的新表的方式拆分“值”列。 “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;

如果有多个分隔符,有人知道如何拆分列吗?

【问题讨论】:

  • @Valerica 在那个问题中,他的列有零个或一个分隔符。我正在寻找一个可以做超过 1 个分隔符的 SQL。相似但不一样
  • 你有列中值的列表吗?
  • @Valerica 如果他已经尝试过该问题的解决方案,并且需要进一步的帮助,那么标记为重复是没有帮助的
  • @GordonLinoff 如果你的列表意味着像 csv 文件(或类似的东西),恐怕我没有这个。

标签: sql ms-access split ms-access-2010


【解决方案1】:

要拆分并获取特定值,我更喜欢使用自定义函数。

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

要生成字符串,在即时窗口中:

GenerateSQLSplit "'1,2,3,4,5,6,7'", "','", 6

导致以下表达式返回该字符串的第 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 附加到它的开头,并将其作为查询执行,它按预期返回6。只有你有一个完全可怕的查询,而使用 UDF 你只会有SELECT SplitString("1,2,3,4,5,6,7", ",", 6)

当然,您可以使用GenerateSQLSplit 创建查询(如果项目不在字符串中,我确保它返回一个空字符串,因此您可以使用它来测试是否存在第 n 个元素)。不过我不推荐它,因为查询会很长、效率低且难以维护。

【讨论】:

  • 恐怕我不能使用用户定义的函数,因为有多个数据库存在一个问题,即人们插入了多个值而只允许一个值。 (数据库模板中的错误)。真的在寻找其他人可以复制和粘贴的 SQL 语句,这样问题就解决了。
  • 查看我的编辑以了解如何做到这一点,以及为什么这是一个糟糕的计划
  • 感谢您的回答。你做了很清楚,只用 SQL 来做是一个想法。我花了一段时间才了解您的 SQL 语句中发生了什么以及它是如何创建的。糟糕的是,在我的情况下,用户定义的函数不是最好的解决方案,因为没有太多访问经验的人必须在没有我帮助的情况下完成它。我目前正在考虑一种解决方案,在该解决方案中我运行交替查询,直到所有信息都已传输。但这根本不是一个干净的解决方案,所以我仍在寻找更好的解决方案。
  • 好吧,如果你真的想在联合查询中执行此操作,那么 3 次拆分还不算长:IIf( InStr(InStr(1,column_value,',') +1, column_value,',')&gt; 0, IIf(InStr(InStr(InStr(1,column_value,',') +1, column_value,',') +1, column_value , ',') &lt; 1, Mid(column_value, InStr(InStr(1,column_value,',') +1, column_value,',') +1), Mid(column_value, InStr(InStr(1,column_value,',') +1, column_value,',') +1, InStr(InStr(InStr(1,column_value,',') +1, column_value,',') +1, column_value , ',') - InStr(InStr(1,column_value,',') +1, column_value,',') -1)), "") 在将 Len(',') 替换为 1 之后。
  • 刚刚发现可以进行 10 次拆分,所以我必须找到另一种方法。但是您已经回答了我的问题,非常感谢!
猜你喜欢
  • 2021-08-15
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 1970-01-01
  • 2012-02-27
  • 1970-01-01
  • 2011-11-28
相关资源
最近更新 更多