2016-04-05 6 views
2

Excel VBAを使用し、OleDBを使用してPGSQLに接続しています。残念ながら、oledbは、group byがテーブルに適用されている集計関数の外部のカラムへの参照を許可しないため、データを連結する必要がありますが、データ(latestBMI)を3つの別々のカラムに分割する際に問題がありますeventdate | weight | bmi)、重みとbmiの値は長さが異なりますが、パイプ区切り文字で除算されるためです。デリミタを使用してSQLデータを3列に分割

ここ

テーブルが抽出して次のようになります。

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要素は私の問題です:

私はパイプ区切り文字を使用して3つの別々の列にそれらを得るにはどうすればよい
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 

+0

いくつのレコードがありますか? – FLICKER

+0

何千もの行のデータがある可能性があります – BradleyS

+0

これをmysqlとsql-serverでタグ付けしましたが、あなたの質問ではpostgreを述べています。どのDBMSを実際に使用していますか? –

答えて

0

あなたが最初のデータをフェッチして、テーブルにそのたら、それを分割してOKであれば(あなたがlatestBMIデータが範囲B2であることがわかっている場合:B7)、これを試して

選択。TextToColumns先:=範囲( "B2:B7")、_
     データ型:= xlDelimited、_
      TextQualifier:= xlDoubleQuote、_
      ConsecutiveDelimiter:= Falseの、_
     タブ:= Falseの、_
     セミコロン:= Falseの、コンマ:= Falseの、スペース:=、偽その他:= Trueの場合、_
      OtherChar:= "|"、_      
のFieldInfo:=配列(配列(1,1)、アレイ(2、1)、アレイ(3、1))、_
      TrailingMinusNumbers。 = True

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は機能します。

+0

申し訳ありません私はすべてこれを学んでいるので、これは愚かな質問と思われるかもしれませんが、私はどのようにそれを私の質問に書いていますか? – BradleyS

+0

OKです。最初のクエリを実行する必要があります。結果を返し、INSERT文を返します。それをループし、各ステートメントを実行してデータを挿入する必要があります。もちろん、 – FLICKER

0

データをインポートするコードの後に​​、テキストを使用して列を分けるだけです。

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 
+0

。私はそれを考えていたはずです。偉大なアイデアは – BradleyS

0

さまざまな複雑なSQL /データベースベースのソリューション(Split Strings the Right Wayを参照)がありますが、SQLステートメントの完了後にVBAでデータを処理する方がはるかに簡単です。ですから、列Bの結果をループし、それを分離する必要があり

enter image description here

:それはこのように見える結果を生み出すよう

あなたのコードが見えます。

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 
+0

私はこれに自分自身を辞任の一種。あなたはそれが抽出後にそのように終わることは間違いありません。 sheet1にある現在のvbaコードの下に直接コードを置くことはできますか? – BradleyS

+0

はい、既存のコードのすぐ下に置くことができます。 'numwows'を設定する直前に' set ws = ThisWorkbook.Sheets( "Sheet1") 'という行を追加してください。うまくいくはずです。 – PeterT

+0

それもうまくいきました。ありがとうございました – BradleyS

関連する問題