【问题标题】:Split SQL data into 3 columns using delimiter使用分隔符将 SQL 数据拆分为 3 列
【发布时间】:2016-07-25 23:44:42
【问题描述】:

我正在使用 Excel VBA 并使用 OleDB 连接到 PGSQL。不幸的是,oledb 不允许引用聚合函数之外的列,其中 group by 已应用于表,因此我必须连接数据,但我无法将数据 (latestBMI) 拆分回 3 个单独的列 ( eventdate|weight|bmi),因为 weight 和 bmi 值的长度不同,但是用管道分隔符分隔。

这是提取后表格的样子:

master_id :   latestBMI
251       :   2008-05-08|84|26.8
2848      :   1992-11-23|86.71|27.3
2026      :   2002-04-16|105|31.6
22316     :   2014-02-28|107.955|35.1
16633     :   2005-07-04|70|25
9545      :   1997-04-08|82.73|24.9

我一直在尝试各种方法,尝试 SUBSTRING、CHARINDEX、LEN、LEFT|RIGHT,但都失败了。 这是我当前的代码,但重量和 bmi 的 SUBSTRING 元素是我的问题:

Const sqlconnection = "Provider=oledb;"

Dim conn As New Connection
conn.ConnectionString = sqlconnection
conn.Open
Dim rs As Recordset

Sheets("Sheet1").Select
Range("A1").Select

Dim DATA As String
DATA = "SELECT latest.master_id, " _
& "SUBSTRING(latestBMI,1,10) eventdate, " _
& "SUBSTRING(latestBMI,12,CHARINDEX('|',latestBMI,RIGHT(latestBMI,7)) weight, " _
& "SUBSTRING(latestBMI,20,4) BMI " _
& "FROM ( " _
& "SELECT master_id, " _
& "MAX(CAST(eventdate AS VARCHAR(10)) + '|' + RIGHT(weightkg,7)+ '|' + RIGHT(bmi,4)) AS latestBMI " _
& "FROM weight " _
& "GROUP BY master_id) as latest " _
& "LEFT JOIN person p on latest.master_id = p.entity_id "

Set rs = conn.Execute(DATA)
With ActiveSheet.QueryTables.Add(Connection:=rs, Destination:=Range("A1"))
    .Refresh
End With

如何使用管道分隔符将它们分成 3 个单独的列?

【问题讨论】:

  • 你有多少条记录?
  • 可能有数千行数据
  • 你已经用 mysql 和 sql-server 标记了这个,但在你的问题中你声明了 postgre。您实际使用的是哪个 DBMS??

标签: mysql sql-server vba excel


【解决方案1】:

我假设您的表格有 4 列

master_id、BMI1、BMI2、BMI3 和 BMI4

您可以使用以下查询生成 INSERT 语句,然后在您的数据库上运行它们

select 'insert into newTable (master_id, BMI1, BMI2, BMI3) values( ' +
   cast(master_id as varchar) + ',''' + replace(latestBMI, '|', ''',''') + ''')'
from #t

它生成以下语句(使用您的示例数据)

insert into newTable (master_id, BMI1, BMI2, BMI3) values( 251,'2008-05-08','84','26.8')
insert into newTable (master_id, BMI1, BMI2, BMI3) values( 2848,'1992-11-23','86.71','27.3')
insert into newTable (master_id, BMI1, BMI2, BMI3) values( 2026,'2002-04-16','105','31.6')
insert into newTable (master_id, BMI1, BMI2, BMI3) values( 22316,'2014-02-28','107.955','35.1')
insert into newTable (master_id, BMI1, BMI2, BMI3) values( 16633,'2005-07-04','70','25')
insert into newTable (master_id, BMI1, BMI2, BMI3) values( 9545,'1997-04-08','82.73','24.9')

如果列不是整数,您可以修改 SELECT 语句以获得您需要的内容。但即使您的列是数字,生成的 INSERT 仍然可以工作。

【讨论】:

  • 对不起,我只是在学习这一切,所以这似乎是一个愚蠢的问题,但我该如何将它写入我的查询中?
  • 没关系。您需要运行第一个查询。它返回结果,包含 INSERT 语句。那么你需要循环并执行每个语句来插入数据。
【解决方案2】:

如果您可以先获取数据,然后在表格中将其拆分,请尝试此操作(如果您知道最新的 BMI 数据将在 B2:B7 范围内)

Selection.TextToColumns 目标:=Range("B2:B7"), _
数据类型:=xlDelimited,_
TextQualifier:=xlDoubleQuote, _
连续分隔符:=假,_
制表符:=假,_
分号:=False,逗号:=False,空格:=False,其他:=True,_
其他字符:="|", _
FieldInfo:=Array(Array(1, 1), Array(2, 1), Array(3, 1)), _
TrailingMinusNumbers:=True

【讨论】:

    【解决方案3】:

    有多种复杂的基于 SQL/数据库的解决方案(参见Split Strings the Right Way),在 SQL 语句完成后,在 VBA 中处理数据会容易得多。

    您的代码看起来会产生如下所示的结果:

    因此,您应该遍历 B 列中的结果并将其分开。

    Option Explicit
    
    Sub test()
        SeparateFields ActiveSheet
    End Sub
    
    Sub SeparateFields(ws As Worksheet)
        '--- assumes your concatenated field (after your SQL
        '    statement) ends up in column B. The separated
        '    fields go in columns B, C, D.
        Dim concatFields As String
        Dim fields() As String
        Dim numRows As Long
        Dim i As Long
        numRows = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
        For i = 2 To numRows
            concatFields = ws.Cells(i, 2).value
            fields = Split(concatFields, "|", , vbTextCompare)
            ws.Cells(i, 2).value = fields(0)
            ws.Cells(i, 3).value = fields(1)
            ws.Cells(i, 4).value = fields(2)
        Next i
    End Sub
    

    【讨论】:

    • 我有点听天由命了。你是对的,提取后确实会这样。我可以将代码直接放在 sheet1 上的当前 vba 代码下吗?
    • 是的,你可以直接把它放在你现有的代码下。在设置numRows 之前添加一行set ws = ThisWorkbook.Sheets("Sheet1"),它应该可以正常工作。
    【解决方案4】:

    在导入数据的代码之后,只需使用文本到列来分隔它。

        Sub SepDelCol()
           Columns("B:B").Select
           Selection.TextToColumns _
           Destination:=Range("B:B"), _
           DataType:=xlDelimited, _
           TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, _
           Tab:=False, Semicolon:=False, Comma:=False, Space:=False, _
           Other:=True, OtherChar:="|"
         End Sub
    

    【讨论】:

    • 当然。我应该想到的。好主意,谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-25
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多