2013-08-14 5 views
6

Queste due istruzioni sono simili ma la seconda causa l'arresto anomalo di Excel ogni volta che viene eseguito. L'unica differenza è tra il model e model return updated rows (ho appositamente progettato questo esempio minimo in modo che le query restituiscono gli stessi dati in entrambi i casi, il mio SQL mondo reale è diverso, naturalmente):Come posso aggirare Excel in modo anomalo con determinate istruzioni 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 
    

è questo un esempio isolato di un bug in ADO o c'è una classe nota di istruzioni SQL che fanno cadere il parser (io non sono nemmeno sicuro perché ADO sarebbe analizzare l'istruzione, piuttosto che solo di passaggio è t attraverso il database).

Ecco il codice VBA in pieno per la versione che si blocca:

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 

In risposta a un commento, ho provato lo stesso SQL utilizzando DAO, e al mio stupore, abbiamo ottieni lo stesso risultato. Il seguente codice si blocca Excel, ma la rimozione del return updated rows è tutto quello che serve per farlo funzionare come previsto:

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

aggiungere 'Set lConn = Nothing' sotto' lConn.Close' per il collegamento gratuito alla connessione. Ora, Excel si blocca anche con l'associazione tardiva di ADODB.Recordset? Vedi anche [suggerimento] (http://www.vbforums.com/showthread.php?511763-Classic-VB-Why-shouldn-tI-use-quot-Dim-As-New-quot) relativo all'utilizzo di 'As new'. Che ne dici di utilizzare le alternative ADODB? Facci sapere se uno di questi aiuti –

+0

Grazie, ho provato ad aggiungere 'set lConn = Nothing' e ho aggiornato la domanda con quel miglioramento. Ho anche provato l'associazione tardiva (vedi le righe commentate nella domanda modificata.) Nessuno dei due previene il crash, sarei interessato a sapere quali alternative ADODB suggeriresti di provare? –

+0

Il primo a cui riesco a pensare è [DAO] (http://allenbrowne.com/ser-29.html). Un'altra opzione sarebbe quella di scrivere la tua libreria COM usando C# o VB.NET e aggiungere riferimenti alla tua 'dll' (come aggiungere altri riferimenti, ad esempio Microsoft Scripting Libreria) .Utilizzando una libreria COM è possibile creare oggetti personalizzati del proprio tipo in Excel. Detto questo, ti consentirebbe di passare le query direttamente alla libreria COM che la eseguirà sul tuo database saltando il parser ADODB ecc. usa 'Connessione SQL' dalla libreria' System.Data.SqlClient'. –

risposta

2

questo è più di una soluzione, rispetto alla soluzione, ma potrebbe essere un'opzione per nascondere eventuali istruzioni SQL, ADO sconvolgente (o Excel, per quella materia), dietro VIEW. Per le istruzioni dinamiche (ovvero, la modifica delle visualizzazioni in fase di esecuzione) è possibile prendere in considerazione l'utilizzo di procedure con EXECUTE IMMEDIATE CREATE OR REPLACE VIEW ... in esse.

+1

Questo è più o meno quello che ho fatto, grazie. ADO sembra abbastanza soddisfatto di "lConn.Execute" crea vista v_sidNNN come "& sSQL" 'e' seleziona * da v_sidNNN'. –

1

È possibile evitare la sintassi fastidioso con la costruzione di una versione personalizzata di return updated rows.

Aggiungi una colonna falso per tenere traccia di ciò che è stato aggiornato e inizializzarlo su falso (0). Quindi aggiungi una misura e per ogni regola crea una regola simile che imposterà il flag su true (1). Infine, aggiungi un predicato per includere solo le righe in cui il flag è 1.

Questa non è chiaramente una soluzione ideale. Sarà più lento. E devi ricordare di costruire tutte le regole extra che popolano la bandiera.

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 

Aggiornamento

Qui ci sono un paio di idee.

  1. È possibile passare al software Oracle? La prima subroutine funziona per me se utilizzo Provider=ORAOLEDB.ORACLE. E la tua seconda subroutine funziona se utilizzo un DSN Oracle. Non riesco a ottenere MSDAORA o {Microsoft ODBC for Oracle} per collegarmi affatto sulla mia macchina. (Anche se probabilmente è colpa mia.)
  2. Prova a cambiare model return updated rows a model keep nav return updated rows main main_model. Questo è un cambiamento semanticamente privo di significato, ma solo elenca esplicitamente i valori predefiniti. Ma forse è sufficiente per evitare il bug di analisi che stai incontrando.
+1

Sapevo già di poterlo aggirare in questo modo, ma apprezzo lo sforzo, grazie. Probabilmente lo sai ma non devi aggiungere 'is_updated_or_inserted' alla tabella di origine, puoi [aggiungerlo alle misure] (http://sqlfiddle.com/#!4/d41d8/15863). –

+0

Buoni suggerimenti, ho già provato a giocare attorno all'inserimento di commenti all'interno della clausola 'return updated rows', ma né quella né il testo completo' keep nav return updated rows main_model' ha alcun effetto. Al momento non abbiamo il provider Oracle installato nel nostro ambiente per testare. Ho raggiunto il punto in cui penso che andrò con una soluzione alternativa: probabilmente creando e rilasciando viste con il sid nel nome. –

Problemi correlati