2013-08-14 93 views
6

Te dwie instrukcje są podobne, ale druga powoduje awarię programu Excel za każdym razem, gdy jest wykonywana. Jedyna różnica jest między model i model return updated rows (mam specjalnie zaprojektowany ten minimalny przykład tak, że kwerendy powrócić dokładnie te same dane, w każdym przypadku, mój świecie rzeczywistym SQL różni się oczywiście):Jak mogę obejść awarie programu Excel z niektórymi instrukcjami SELECT?

  1. select * 
    from(select * 
         from (select 1 id, 100 val from dual 
          union all 
          select 2 id, 200 val from dual) 
         model 
         dimension by (id) 
         measures (val) 
         rules (val[1] = val[cv()]+1)) 
    where val=101 
    
  2. select * 
    from(select * 
         from (select 1 id, 100 val from dual 
          union all 
          select 2 id, 200 val from dual) 
         model return updated rows 
         dimension by (id) 
         measures (val) 
         rules (val[1] = val[cv()]+1)) 
    where val=101 
    

Czy to odosobniony przykład błąd w ADO lub tam jest znaną klasą SQL że katastrofie parsera (nie jestem nawet pewien, dlaczego ADO będzie analizować oświadczenia zamiast tylko przejazdem to t do bazy danych).

Oto kod VBA w całości do wersji, która wywala:

Option Explicit 
Sub Go() 

    Dim lConn As ADODB.Connection 
    Dim lRecordset As ADODB.Recordset 
    'Dim lRecordset 
    Dim sSQL As String 

    Set lConn = New ADODB.Connection 
    Set lRecordset = New ADODB.Recordset 
    'Set lRecordset = CreateObject("ADODB.Recordset") 

    lConn.Open "Provider=MSDAORA;Data Source=(DESCRIPTION=(CID=GTU_APP)(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=devdb)(PORT=1521)))(CONNECT_DATA=(SID=oracle)(SERVER=DEDICATED)));User Id=csuk;Password=thisisnotmyrealpassword;" 

    With lRecordset 
     sSQL = "select * " & _ 
       "from(select * " & _ 
       "  from (select 1 id, 100 val from dual " & _ 
       "    Union all " & _ 
       "    select 2 id, 200 val from dual) " & _ 
       "  model return updated rows " & _ 
       "  dimension by(id) " & _ 
       "  measures (val) " & _ 
       "  rules (val[1] = val[cv()]+1)) " & _ 
       "where val=101" 
     .Open sSQL, lConn 
     While Not .EOF 
      Sheets(1).Cells(1, 1) = ![Val] 
      .MoveNext 
     Wend 
     .Close 
    End With 

    Set lRecordset = Nothing 
    lConn.Close 
    Set lConn = Nothing 

End Sub 

W odpowiedzi na komentarz, próbowałem tego samego SQL przy użyciu DAO, a do mojej konsternacji, my uzyskać ten sam wynik. Poniższy kod awarii Excel, ale usunięcie return updated rows jest potrzebny, aby działać zgodnie z oczekiwaniami:

Option Explicit 
Sub Go() 

    Dim lWorkspace As DAO.Workspace 
    Dim lDatabase As DAO.Database 
    Dim lRecordset As DAO.Recordset 

    Dim sSQL As String 

    sSQL = "select * " & _ 
      "from(select * " & _ 
      "  from (select 1 id, 100 val from dual " & _ 
      "    Union all " & _ 
      "    select 2 id, 200 val from dual) " & _ 
      "  model return updated rows " & _ 
      "  dimension by(id) " & _ 
      "  measures (val) " & _ 
      "  rules (val[1] = val[cv()]+1)) " & _ 
      "where val=101" 

    Set lWorkspace = DBEngine.Workspaces(0) 
    Set lDatabase = lWorkspace.OpenDatabase("", False, False, "Driver={Microsoft ODBC for Oracle};Server=devdb:1521/oracle;Uid=charts_csuk_uksoft;Pwd=thisisnotmyrealpassword;") 
    Set lRecordset = lDatabase.OpenRecordset(sSQL, dbOpenDynaset, dbSQLPassThrough) 

    With lRecordset 
     While Not .EOF 
      Sheets(1).Cells(1, 1) = ![Val] 
      .MoveNext 
     Wend 
    End With 

    Set lRecordset = Nothing 
    Set lDatabase = Nothing 
    Set lWorkspace = Nothing 

End Sub 
+0

add 'Set lConn = Nothing' poniżej' lConn.Close' aby uwolnić połączenie z połączeniem. Czy program Excel ulega awarii z późnym wiązaniem zestawu ADODB.Recordset? Zobacz także [tip] (http://www.vbforums.com/showthread.php?511763-Classic-VB-Dlaczego- nie----)-Dim-As-New-quot) odnoszące się do używania 'As Nowy ". Co powiesz na używanie alternatyw ADODB? Daj nam znać, jeśli któraś z nich pomoże –

+0

Dzięki, próbowałem dodać 'set lConn = Nothing' i zaktualizowałem pytanie o tę poprawkę. Próbowałem również późnego wiązania (zobacz skomentowane wiersze w edytowanym pytaniu, żadne z nich nie zapobiegnie awarii, chciałbym wiedzieć, jakie alternatywy ADODB chciałbyś zasugerować? –

+0

Pierwszym, o którym mogę pomyśleć, jest [DAO] (http://allenbrowne.com/ser-29.html) .Inną opcją byłoby napisanie własnej biblioteki COM przy użyciu C# lub VB.NET i dodanie odniesień do 'dll' (tak samo jak dodanie innych referencji, np. Microsoft Scripting Biblioteka) .Korzystanie z biblioteki COM pozwala na tworzenie własnych obiektów własnego typu w programie Excel Powiedział, że umożliwiłoby to przekazywanie kwerend bezpośrednio do biblioteki COM, która wykonywałaby go w bazie danych pomijając parser ADODB itp. użyj 'SQL Connection' z biblioteki' System.Data.SqlClient'. –

Odpowiedz

2

Jest to raczej obejście, niż rozwiązanie, ale może to być opcja ukrywania instrukcji SQL, powodując ADO (lub Excel), za VIEW. W przypadku instrukcji dynamicznych (tj. Zmieniających widoki w czasie wykonywania) można rozważyć użycie procedur z EXECUTE IMMEDIATE CREATE OR REPLACE VIEW ... w nich.

+1

To jest mniej więcej to, co zrobiłem, dzięki. ADO wydaje się być całkiem zadowolony z 'lConn.Execute 'create view v_sidNNN jako" & sSQL "' i 'select * from v_sidNNN'. –

1

Można uniknąć kłopotliwego składni budując niestandardową wersję return updated rows.

Dodaj fałszywą kolumnę, aby śledzić, co zostało zaktualizowane, i zainicjuj ją jako fałsz (0). Następnie dodaj miarę, a dla każdej reguły utwórz podobną regułę, która ustawi flagę na true (1). Na koniec dodaj predykat, aby uwzględnić tylko wiersze, w których flaga jest 1.

To zdecydowanie nie jest idealne rozwiązanie. Będzie wolniej. I musisz pamiętać, aby zbudować wszystkie dodatkowe reguły, które wypełniają flagę.

select id, val 
from(select * 
     from (select 1 id, 100 val, 0 is_updated_or_inserted from dual 
      union all 
      select 2 id, 200 val, 0 is_updated_or_inserted from dual 
      union all 
      select 3 id, 101 val, 0 is_updated_or_inserted from dual) 
     model 
     dimension by (id) 
     measures (val, is_updated_or_inserted) 
     rules (val[1] = val[cv()]+1 , is_updated_or_inserted[1] = 1)) 
where val=101 
    and is_updated_or_inserted = 1 

Aktualizacja

Oto kilka innych pomysłów.

  1. Czy możesz przełączyć się na oprogramowanie Oracle? Twój pierwszy podprogram działa dla mnie, jeśli używam Provider=ORAOLEDB.ORACLE. A drugi podprogram działa, jeśli korzystam z Oracle DSN. Nie mogę uzyskać MSDAORA lub {Microsoft ODBC for Oracle}, aby połączyć się w ogóle na moim komputerze. (Chociaż to prawdopodobnie moja wina).
  2. Spróbuj zmienić model return updated rows na model keep nav return updated rows main main_model. Jest to zmiana nieistotna semantycznie, po prostu jawnie wyświetla wartości domyślne. Ale być może wystarczy, aby uniknąć błędu parsowania, na który się natknąłeś.
+1

Już wiedziałem, że mogę obejść to tak, ale doceniam wysiłek, dziękuję. Prawdopodobnie wiesz o tym, ale nie musisz dodawać 'is_updated_or_inserted' do tabeli źródłowej, możesz [możesz dodać to do miar] (http://sqlfiddle.com/#!4/d41d8/15863). –

+0

Dobre sugestie, już próbowałem odtwarzać wstawianie komentarzy w klauzuli 'return updated rows', ale ani ten, ani pełny tekst' keep nav return updated rows main main_model' nie przynosi żadnego efektu. Obecnie nie mamy zainstalowanego w naszym środowisku dostawcy Oracle do przetestowania. Osiągnąłem etap, w którym myślę, że pójdę z obejściem: prawdopodobnie tworzenie i upuszczanie widoków z sid w nazwie. –