4

私は解決策を探すのに2日間費やしましたが、これは私を狂わせています...

まず、私が何をしているのかを説明させてください。50 万件のレコードを取り込み、これらのレコードが 12 個のピボット テーブルを動かしています。ワークブックを扱いやすいファイル サイズに保つために、ピボット テーブルを外部データ接続から直接作成しました。手動で構成したodbc接続です。

ワークブックで「すべて更新」を押すと、すべてのピボット テーブルが自動的に更新されます。

しかし今、手動の開始日と終了日でレコードセット全体を制限できるようにする必要があります...ピボットテーブルの日付フィルターを変更することは理想的ではありません.終了日の影響を受けるのは単一のフィールドだけではないため、フィールドがありますピボットの前に計算する必要があり、終了日を含む数式に依存する値を持っています。

午後に何度も Excel をクラッシュさせた後、ピボット テーブルに直接接続している場合は ? を使用できないという制限があることに気付きました。パラメータ ダイアログでセル参照を指定すると、ブックを閉じるとセル参照が失われます。

したがって、私の次のアプローチはこれを行うことでした:

Dim ReportStartDate, ReportEndDate

' Get parameters from Intro sheet
ReportStartDate = "'" & ActiveWorkbook.Worksheets("Intro").Range("$B$1").Value & "'"
ReportEndDate = "'" & ActiveWorkbook.Worksheets("Intro").Range("$B$2").Value & "'"

' There are 3 directpivot odbc connections/caches that need to be modified.
' In each query, the default report-end-date is specified by CURDATE().
' The default report-start-date is specified as '2010-01-01'
' Replace these defaults with the values retrieved above.

Dim cn As WorkbookConnection
Dim odbcCn As ODBCConnection
Dim originalsqltext, newsqltext

For Each cn In ThisWorkbook.Connections     ' loop through the connections
    If cn.Type = xlConnectionTypeODBC Then
        Set odbcCn = cn.ODBCConnection
        originalsqltext = odbcCn.CommandText
        If odbcCn.Parent = "Calls" Then
            newsqltext = Replace(originalsqltext, "CURDATE()", ReportEndDate)
            newsqltext = Replace(newsqltext, "'2010-01-01'", ReportStartDate)
        ElseIf odbcCn.Parent = "Suboutcomes" Then
            newsqltext = Replace(originalsqltext, "CURDATE()", ReportEndDate)
            newsqltext = Replace(newsqltext, "'2010-01-01'", ReportStartDate)
        ElseIf odbcCn.Parent = "QtyCallsPerDay1" Then
            newsqltext = Replace(originalsqltext, "CURDATE()", ReportEndDate)
        Else
            newsqltext = originalsqltext
        End If
        odbcCn.CommandText = newsqltext
        odbcCn.Refresh
        odbcCn.CommandText = originalsqltext
    End If
    cn.Refresh ' refresh the other connection without modification
Next
Set cn = Nothing
Set odbcCn = Nothing

しかし、odbcCn.CommandText = newsqltext 実行時エラー '1004: アプリケーション定義またはオブジェクト定義のエラーになると、エラーが発生します。これはあまり役に立ちません...

newsqltext に意図したものが含まれていることを確認しましたが、CommandText に割り当てられません。

もう 1 日グーグルで検索し、いくつかの簡単なマクロ記録実験を行った結果、CommandText を変更するには次のような構文が必要なようです。

.CommandText = Array( _
"SELECT C1.CALLID, C1.TAKENON, C1A.TAKENAT, CAST(CONCAT(DATE_FORMAT(TAKENON,'%c/%e/%y'),' ',TIME_FORMAT(TAKENAT,'%H:" _
    , _
    "%i:%s')) AS CHAR) AS CallDateTime, YEAR(C1.TAKENON) AS Year, CEILING(MONTH(C1.TAKENON)/3) AS Quarter, MONTH(C1.TAKE" _
    , _

(巨大なので残りは省略します)...最初にマクロを記録しようとしたときに「行の継続が多すぎます」というエラーが発生したため、最初はそれが私の問題だと思ったので、クエリを短くしました可能な限り、置換前に 1428 文字に減らします。置換後、1448文字になります...しかし、コードが必要とする配列形式に解析するにはどうすればよいですか? または、これを行うためのより良い方法はありますか?

vbaで編集できるようにするためだけに、このようにクエリを台無しにしたくありません.CommandTextを変更する方法について何かが欠けているように感じます...

最初に oledb に変更しない限り odbc 接続で CommandText を変更できないというこの問題のように、私の検索で見つかったいくつかの厄介なことがありました。その後、CommandText を変更してから、接続をodbc ...しかし、それはExcel 2010より前で、これらを使用しなくなりました... http://p2p.wrox.com/excel-vba/29037-cant-set-commandtext-property-if-cache-has- 1-rpt.html

そこにリンクされている KnowledgeBase の記事http://support.microsoft.com/kb/816562は、さらに驚くべきものです... StringToArray 関数を見たときに解決策を見つけたと思いましたが、さらに読んで見ました

注: 共有ピボットキャッシュ、OLAP ベースのピボットテーブル、または複数集計範囲ベースのピボットテーブルを使用してデータベースに接続している場合、上記のコードは期待どおりに機能しない可能性があります。

その後

ワークシート上の複数のピボットテーブルが同じピボットテーブルから派生している場合、最初のピボットテーブルを処理した後、サブルーチンは機能しません。2003 年 3 月現在、この問題に対する既知の回避策はありません。

ただし、この記事は Excel 2000 ~ 2003 にのみ適用されることに注意してください。

私が試したもう1つのことは、おそらく使用できると思いましたか?パラメータを設定し、vba で設定するだけです...しかし、パラメータを使用して簡単なクエリを作成し、パラメータを新しいセル参照にポイントしている間にマクロを記録すると、マクロにはこれだけが含まれていました: Sub PARAMEDIT5() ' ' PARAMEDIT5 Macro '

'
    With ActiveWorkbook.Connections("PARAMEDIT").ODBCConnection
        .BackgroundQuery = False
        .CommandText = Array("SELECT * FROM Calls1 where TAKENON > ?" _
        )
        .CommandType = xlCmdSql
        .Connection = _
        "ODBC;DRIVER={MySQL ODBC 5.1 Driver};UID=xxxxxxx;PWD=xxxxxxxx;SERVER=xxxxxx;PORT=3306;BIG_PACKETS=1;"
        .RefreshOnFileOpen = False
        .SavePassword = True
        .SourceConnectionFile = ""
        .SourceDataFile = ""
        .ServerCredentialsMethod = xlCredentialsMethodIntegrated
        .AlwaysUseConnectionFile = False
    End With
    With ActiveWorkbook.Connections("PARAMEDIT")
        .Name = "PARAMEDIT"
        .Description = ""
    End With
    ActiveWorkbook.Connections("PARAMEDIT").Refresh
End Sub

直接ピボット タイプの接続と、パラメーターをサポートすることがわかっている外部データ ソースに接続された通常のテーブルの両方でこれを試しました。

だから...共有ピボットキャッシュodbc接続のクエリをパラメータ化する正しい方法を知っている人はいますか?

更新:私はこれを試しました:

Dim cn, originalCn, newCn As WorkbookConnection
Dim odbcCn As ODBCConnection
Dim originalsqltext, newsqltext
Dim connStr As String

For Each cn In ThisWorkbook.Connections     ' loop through the connections
    If cn.Type = xlConnectionTypeODBC Then
        Set odbcCn = cn.ODBCConnection
        originalsqltext = odbcCn.CommandText
        Set originalCn = cn
        connStr = odbcCn.Connection
        Select Case odbcCn.Parent
            Case "Calls", "Suboutcomes"
                newsqltext = Replace(originalsqltext, "CURDATE()", ReportEndDate)
                newsqltext = Replace(newsqltext, "'2010-01-01'", ReportStartDate)
            Case "QtyCallsPerDay1"
                newsqltext = Replace(originalsqltext, "CURDATE()", ReportEndDate)
            Case Else
                newsqltext = originalsqltext
        End Select
        Set newCn = ActiveWorkbook.Connections.Add(odbcCn.Parent & "New", "WhoCares", connStr, newsqltext)
        Set cn = newCn
        cn.Refresh
        Set cn = originalCn
        newCn.Delete
    Else
        cn.Refresh ' refresh any other connections without modification
    End If
Next

Set cn = Nothing
Set odbcCn = Nothing
Set newCn = Nothing
Set originalCn = Nothing

そして、コマンドテキストを必要なものにするという点で、私が望むことをしているように見えますが、ステップスルーしても cn.Refresh は何もしません。更新されていても、ピボットが更新されていない場合、Calls1 を探している場所を確認でき、更新が発生した瞬間に Calls1New という名前が付けられていますが、接続は何もしていません (クエリは通常、完了するまでに数分かかります)。それとも、同じ名前の既存の接続に割り当てることができないのでしょうか? cn = newCn を設定すると、どちらも同じ名前でまったく同じに見えます。

もう少し調べてみますが、他の誰かがこのようなことをしたことがあれば、もっと助けていただければ幸いです. あなたがこれまでに与えてくれたものに感謝します!

編集:だから私は元に戻っています

odbcCn.CommandText = newsqltext
cn.Refresh
odbcCn.CommandText = originalsqltext

http://support.microsoft.com/kb/816562で見つけた odbcCn.CommandText = StringToArray(newsqltext) cn.Refresh odbcCn.CommandText = StringToArray(originalsqltext) も試しました。どちらも機能しませんでした。

エラーの直前にあるので、originalsqltext と newsql text を投稿します。newsqltext と同様に、元の sqltext をクエリのダイアログ ボックスに手動で貼り付けると、元のsqltext が正常に機能することに注意してください。

**新しい情報のため、以前の編集を削除しました**

注 -同様の問題のように思われるスレッドExcel VBA: Update Pivot Sourcedataを見つけました。ただし、このスレッドは2009年のものなので、Excel 2010を使用していない可能性が高いです。

For Each pvtC In ThisWorkbook.PivotCaches
    name = pvtC.WorkbookConnection.name
    originalsqltext = pvtC.CommandText
    pvtC.CommandText = originalsqltext
Next

pvtC.CommandText = originalsqltextでも失敗します

更新: これはクエリ自体とは何の関係もありませんが、複数のピボット テーブルが同じピボットキャッシュを指しているという条件であると確信しています。簡単なクエリで新しい外部データソースを作成しました

SELECT * FROM clientdashboard1.Calls1 WHERE TAKENON BETWEEN '2010-01-01' AND CURDATE()

そのクエリとして。接続に AlphaTest という名前を付け、そこからピボット テーブルを作成し、そのピボット テーブルを別のシートにコピーして、別のフィールドを使用しました。最初にこれを実行するようにコードを変更しました。

For Each pvtC In ThisWorkbook.PivotCaches
    name = pvtC.WorkbookConnection.name
    If name = "AlphaTest" Then
        originalsqltext = pvtC.CommandText
        pvtC.CommandText = originalsqltext
    End If
Next

まったく同じ時点で失敗しました pvtC.CommandText = originalsqltext

次に、2 番目のピボット テーブルを削除し、もう一度実行したところ、機能しました。

次に、念のため、元の巨大なクエリを挿入して、もう一度実行しました。出来た。ただし、別のしわが明らかになりました...コードを介して CommandText を変更すると、更新されます。したがって、置換を行い、更新を行ってから元に戻すという私の最初の計画は、2番目の割り当てでテーブルが再び更新されるため、機能しません(機能した場合)。

アップデートこれはますます良くなっています。おそらく1つのレコードだけで、ピボットキャッシュのダミーコピーを作成することについて考えました1。レポート タスクを実行します (シートをコピーし、リンクを解除し、名前を付けて保存し、閉じるのが通常の方法です)。次に、元のブックに戻り、すべてのピボット テーブルをそれぞれのダミー キャッシュにポイントします。さて、私が持っていた AlphaTest データソースを知っていますか? pvtC.CommandText = originalsqltext が実際にクエリを変更し、AlphaTest を更新させたと思いました...ああ、私の友人。これは、AlphaTest のコピーである Connection と呼ばれる新しい接続を作成しました。いいよ。これをどのように使用できますか?..... 試してみたいアイデアがいくつかありますが、他の誰かがこれに対処した場合は、

4

5 に答える 5

3

オンラインで多くの調査を行った後...これはCommandTextODBC接続のプロパティを更新するときのバグであることがわかりました。一時的に OLEDB 接続にCommandText切り替え、プロパティを更新してから ODBC に戻すと、新しい接続は作成されません。理由を聞かないでください...これは私にとってはうまくいきます。

新しいモジュールを作成し、次のコードを挿入します。

Option Explicit

Sub UpdateWorkbookConnection(WorkbookConnectionObject As WorkbookConnection, Optional ByVal CommandText As String = "", Optional ByVal ConnectionString As String = "")

With WorkbookConnectionObject
    If .Type = xlConnectionTypeODBC Then
        If CommandText = "" Then CommandText = .ODBCConnection.CommandText
        If ConnectionString = "" Then ConnectionString = .ODBCConnection.Connection
        .ODBCConnection.Connection = Replace(.ODBCConnection.Connection, "ODBC;", "OLEDB;", 1, 1, vbTextCompare)
    ElseIf .Type = xlConnectionTypeOLEDB Then
        If CommandText = "" Then CommandText = .OLEDBConnection.CommandText
        If ConnectionString = "" Then ConnectionString = .OLEDBConnection.Connection
    Else
        MsgBox "Invalid connection object sent to UpdateWorkbookConnection function!", vbCritical, "Update Error"
        Exit Sub
    End If
    If StrComp(.OLEDBConnection.CommandText, CommandText, vbTextCompare) <> 0 Then
        .OLEDBConnection.CommandText = CommandText
    End If
    If StrComp(.OLEDBConnection.Connection, ConnectionString, vbTextCompare) <> 0 Then
        .OLEDBConnection.Connection = ConnectionString
    End If
    .Refresh
End With

End Sub

このUpdateWorkbookConnectionサブルーチンは、OLEDB または ODBC 接続の更新でのみ機能します。接続は必ずしもピボット テーブルにリンクする必要はありません。また、別の問題が修正され、同じ接続に基づくピボット テーブルが複数ある場合でも接続を更新できるようになります。

更新を開始するには、次のように、接続オブジェクトとコマンド テキスト パラメータを指定して関数を呼び出すだけです。

UpdateWorkbookConnection ActiveWorkbook.Connections("Connection"), "exec sp_MyAwesomeProcedure"

オプションで、接続文字列も更新できます。

私は?パラメータを使用したことがないので、これで問題が解決するかどうかはわかりませんが、そうなると思います。私は常に、文字列連結を使用して直接 CommandText 文字列にパラメータを挿入しています。

于 2015-06-24T16:33:19.637 に答える
2

私は常に ODBC 接続を使用しています。まず、ワークシートで手動で接続を確立します。「バックグラウンド更新を有効にする」がオフになっていることを確認します。私は一日中このようなことをしています。接続を更新するための簡単なコードを次に示します (必要に応じて変数を暗くします)。

ActiveWorkbook.Connections("ExampleConnection").Refresh

コマンド テキストを変更するには:

ActiveWorkbook.Connections("ExampleConnection").ODBCConnection.CommandText = _
"SELECT FILE1.FIELD1 AS ""Name1"", FILE1.FIELD2 as ""Name2""" & chr(13) & "" & chr(10) & chr(13) & "" & chr(10) & _
"FROM SERVER.LIBRARY.FILE1 FILE1" & chr(13) & "" & chr(10) & chr(13) & "" & chr(10) & _
"WHERE FILE1.FIELD1 = 'FILTER'"
ActiveWorkbook.Connections("ExampleConnection").Refresh

ランタイム変数を使用してコマンド テキストを変更するには、次のようにします。

DIM str AS STRING

str = "VARIABLE"

ActiveWorkbook.Connections("ExampleConnection").ODBCConnection.CommandText = _
"SELECT FILE1.FIELD1 AS ""Name1"", FILE1.FIELD2 as ""Name2""" & chr(13) & "" & chr(10) & chr(13) & "" & chr(10) & _
"FROM SERVER.LIBRARY.FILE1 FILE1" & chr(13) & "" & chr(10) & chr(13) & "" & chr(10) & _
"WHERE FILE1.FIELD1 = '" & str & "'"
ActiveWorkbook.Connections("ExampleConnection").Refresh

また、複数のピボットを更新するには、前述のように、ODBC 接続の [バックグラウンド更新を有効にする] チェックボックスがオフになっていることを確認してください。これにより、一日中ピボットを更新できます。

ActiveWorkbook.Connections("ExampleConnection").Refresh
Sheet1.PivotTables("PivotTable1").PivotCache.Refresh
Sheet1.PivotTables("PivotTable2").PivotCache.Refresh
Sheet2.PivotTables("PivotTable1").PivotCache.Refresh
Sheet2.PivotTables("PivotTable2").PivotCache.Refresh

動的 WHERE 句または「行が多すぎます」エラーを回避するためのオプション:

DIM s AS STRING
DIM f AS STRING
DIM w AS STRING
DIM r AS RANGE
Dim str AS STRING

set r = Sheet1.Range("A1")
str = r.Value
s = "SELECT FILE1.FIELD1 as ""Name1"", FILE1.FIELD2 as ""Name2"""
f = "FROM SERVER.LIBRARY.FILE1 FILE1"

If r.Value = "" Then
   w = ""
Else
   w = "WHERE FILE1.FIELD1 = '" & str & "'"
End If

ActiveWorkbook.Connections("ExampleConnection").ODBCConnection.CommandText = _
s & chr(13) & "" & chr(10) & chr(13) & "" & chr(10) & _
f & chr(13) & "" & chr(10) & chr(13) & "" & chr(10) & _
w
ActiveWorkbook.Connections("ExampleConnection").Refresh
于 2013-09-20T13:24:11.123 に答える
0

それは100%動作します

WorkbookConnection wc = book.Connections.Add("SQL-STRING", "", response.ConnectionString, response.SqlString, XlCmdType.xlCmdSql);
pivot = worksheet.PivotTables(1);
pivot.ChangeConnection(wc);
于 2016-01-29T11:18:30.063 に答える
0

これはあなたの質問に対する答えではありませんが、とにかくこれらの提案をしたかったのです。

For Each cn In ThisWorkbook.Connections     ' loop through the connections
    If cn.Type = xlConnectionTypeODBC Then
        Set odbcCn = cn.ODBCConnection
        originalsqltext = odbcCn.CommandText
        Select Case odbcCn.Parent
            Case "Calls", "Suboutcomes"
                newsqltext = Replace(originalsqltext, "CURDATE()", ReportEndDate)
                newsqltext = Replace(newsqltext, "'2010-01-01'", ReportStartDate)
            Case "QtyCallsPerDay1"
                newsqltext = Replace(originalsqltext, "CURDATE()", ReportEndDate)
            Case Else
                newsqltext = originalsqltext
        End Select
        odbcCn.CommandText = newsqltext
        odbcCn.Refresh
        odbcCn.CommandText = originalsqltext
    Else ''' this used to be End If
        cn.Refresh ' refresh the other connection without modification
    End If
Next

2 つのことに注意してください: 私は Select Case を使用しました (ただし、これは私の考えではより良いコードのためであり、機能には何も変わりません)。第 2 に、cn.Refresh を Else ブロックに入れてはいけませんか? コードを誤解している可能性がありますが、元の SQL を再割り当てすると、接続が更新されるようです。

についてはtoo many line continuations、次のように VBA をだますことができます。

somevar = "line 1" & _
          "line 2" & _
          .....
          "line 55"
somevar = somevar & _
          "line 56" & _
          "line 57"

このようにして、技術的に固定数に制限されることはありません& _

さて、あなたの本当の質問に: 1004: Application-defined or object-defined errorSQL 文字列に、プロバイダーが適切に解釈できない何かがあることを意味します。まったく問題ないとおっしゃっていますが、 の内容を掲載していただけnewsqltextないでしょうか。確かに、コーディング エラーを起こしたようには見えないからです。

于 2013-03-29T08:56:06.870 に答える
0

良い一日、

この問題は明らかに、複数のピボット テーブルが接続にアクセスしている場合に発生します。

次の回避策はトリックを行います:

手動 (1 回のみ必要)

1.) 適切な ODBC 接続をファイルとして任意の場所に手動でエクスポートします。(接続をダブルクリックし、「定義」の下にあるボタンを見つけます)

VBA で:

2.) ステップ 1 でエクスポートしたワークブックに接続を追加します。

myWorkbook.Connections.AddFromFile "\myPath\myODBCConnection.odc"

3.) 追加された接続のコマンド テキストを編集します。

myWorkbook.Connections("nameOfAddedConnectionName").ODBCConnection.CommandText = "SELECT * FROM any"

4.) ピボット テーブルがアクセスする接続を削除します。

myWorkbook.Connections("oldPivotConnectionName").Delete

5.) 追加された接続の名前を古い接続の名前に変更します

myWorkbook.Connections("nameOfAddedConnectionName").Name = "oldPivotConnectionName"

6.) 接続を更新する

myWorkbook.Connections("oldPivotConnectionName").Refresh

それでおしまい!:-)

于 2016-03-23T10:49:19.493 に答える