Acceso a Bases de datos SQL Server...

 

Fecha: 04/May/98
Autor: Quique


Acceso a una Base de datos SQL Server utilizando el metodo OpenConnection para establecer una conexión con un origen de datos de un espacion de trabajo ODBCDirect.
Ejecuta consultas de SQL directamente el Server, creando procedimientos almacenados, tablas temporales y borrandolos antes de cerrar la conexión.
El modulo es llamado desde un formulario, pero si se quiere se pueden quitar todas las referencias al formulario y el modulo se ejecutaria sin mensajes.
En este ejemplo creo una tabla en SQL Server y la traspaso a ACCESS 97, pero se podria modificar para que imprimiera un informe en CR, por ejemplo.

Sub Procedimiento_SQL(CdAnio As String)
    Dim wsODBC As Workspace, conODBC As Connection, bd As Database, rs As Recordset, qdfTemp As QueryDef, tdf As TableDef
    Dim SQL_1 As String, SQL_2 As String, MiSQL As String, i As Integer
    
    DoCmd.SetWarnings False  ' Desactiva la presentación de mensajes del sistema 
    DoCmd.Hourglass True 'lleva a cabo la acción RelojDeArena
    
    Forms!T_SQL!Lit_Estado.Caption = "Conectando a Base de Datos"
    DoEvents
    Set wsODBC = CreateWorkspace("", <NOMBRE DE USUARIO>,<PASSWORD>, dbUseODBC)
'Crea un nuevo espacio de trabajo Workspace de ODBCDirect, al establecer  dbUseODBC el motor de base de datos Microsoft Jet no se cargará en memoria y toda actividad se producirá con el origen de datos ODBC identificado el en objeto Connection.

    Set conODBC = wsODBC.OpenConnection("NuevaConexion", dbDriverNoPrompt, True, "ODBC;DATABASE=<NOMBRE BASE DATOS>;UID=<NOMBRE USUARIO>;PWD=<PASSWORD>;DSN=<CREADO EN ODBC32>")
' Establece una conexión con origen de datos en un espacio de trabajo ODBCDirect. DbDriverNoPrompt utiliza la cadena de conexión proporcionada en <nombreBaseDatos> , si no se proporciona suficiente informacion produce un error en tiempo de ejecucion, cambiar a dbDriverPrompt si se desea que el administrador del controlador muestre el cuadro de dialogo.
    
' La siguiente sentencia prepara la sesion en el servidor para una consulta "dirty reads", que no se bloquee ninguna tabla de las que se usen.
    Set qdfTemp = conODBC.CreateQueryDef("") ' los objetos son siempre temporales en ODBCDirect
    With qdfTemp
        .Prepare = dbQUnprepare
        .SQL = "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"
        .ODBCTimeout = 120
        .Execute
    End With
    
'Verificamos que no existe el procedimiento alamcenado en el servidor
    Set qdfTemp = conODBC.CreateQueryDef("")
    MiSQL = "if exists (select * from sysobjects where id = object_id('proced') and sysstat & 0xf = 4)" & _
      " drop procedure proced"
    With qdfTemp
        .Prepare = dbQUnprepare
        .SQL = MiSQL
        .ODBCTimeout = 120
        .Execute
    End With
    
'Verificamos que no existe la tabla auxiliar que creamos como almacenamiento temporal
    Set qdfTemp = conODBC.CreateQueryDef("")
    MiSQL = "if exists (select * from sysobjects where id = object_id('Tmp_ Dist') and sysstat & 0xf = 3)" & _
      " drop table Tmp_Dist"
    With qdfTemp
        .Prepare = dbQUnprepare
        .SQL = MiSQL
        .ODBCTimeout = 120
        .Execute
    End With
 
' Aquí esta el procedimiento almacenado en cuestion. Se pasa como parametro el año, y se utilizan transaccciones con el fin de no bloquear la tempdb.
    Set qdfTemp = conODBC.CreateQueryDef("")
    SQL_1 = "CREATE PROCEDURE Proced (@CdAnio char(4)) AS " & _
            "begin tran " & _
                "SELECT anio_factura AS anio, mes_factura AS mes, id_cliente, id_producto AS id_producto, id_envase AS id_envase, " & _
                    "SUM(kgs) AS Kilos " & _
                    "INTO #tmp_sog " & _
                    "FROM Venta_Direc V " & _
                    "WHERE anio_factura = @CdAnio AND " & _
                    "GROUP BY anio_factura, mes_factura, id_cliente, id_producto, id_envase " & _
            "if @@error != 0 " & _
                "rollback " & _
            "commit tran "
    SQL_2 = "begin tran " & _
                "SELECT id_cliente AS id_Distribuidor, anio, mes, T.id_producto, id_envase, kilos " & _
                    "INTO Tmp_Dist " & _
                    "FROM #tmp_sog T, producto P, familia_nueva F, especialidad E, sublinea S " & _
                    "WHERE T.id_producto = P.id_producto AND " & _
                    "P.id_familia_nueva = F.id_familia_nueva AND " & _
                    "F.id_especialidad = E.id_especialidad AND " & _
                    "E.id_sublinea = S.id_sublinea AND " & _
                    "S.id_linea_nueva IN ('A','I','G','P','D') " & _
                    "ORDER BY id_Distribuidor, anio, mes, T.id_producto, id_envase " & _
            " drop table #tmp_sog " & _
            "if @@error != 0 " & _
                "rollback " & _
            "commit tran "
    MiSQL = SQL_1 + SQL_2
    
' Pasa el procedimiento almacenado a SQL Server
    Forms!T_COMPRAS!Lit_Estado.Caption = "Procesando registros de Base de datos"
    DoEvents
    With qdfTemp
        .Prepare = dbQPrepare
        .SQL = MiSQL
        .ODBCTimeout = 120
        .Execute
    End With
    
'Ojo. Aquí se utiliza un formulario, desde el cual se llama al modulo.
' Aquí es donde se ejecuta la consulta en el servidor
    MiSQL = "EXEC Proced '" & Forms!T_COMPRAS!CdAnio & "'"
    Set qdfTemp = conODBC.CreateQueryDef("")
    With qdfTemp
        .Prepare = dbQUnPrepare
        .SQL = MiSQL
        .ODBCTimeout = 240
        .Execute
    End With
 
    Set qdfTemp = conODBC.CreateQueryDef("")
    MiSQL = "if exists (select * from sysobjects where id = object_id('Proced') and sysstat & 0xf = 4)" & _
      " drop procedure Proced"
    With qdfTemp
        .Prepare = dbQUnprepare
        .SQL = MiSQL
        .ODBCTimeout = 120
        .Execute
    End With
                   
    Forms!T_COMPRAS!Lit_Estado.Caption = "Creando Tabla "
    DoEvents
    
    Set bd = CurrentDb()
    bd.TableDefs.Refresh
    
' Elimina la tabla auxiliar si existe en ACCESS
    For i = (bd.TableDefs.Count) - 1 To 0 Step -1
        If bd.TableDefs(i).Name = "T_COMPRAS" Then
            bd.TableDefs.Delete "T_COMPRAS"
        End If
    Next i
    
	' Traspasa la tabla de SQL Server a la base de datos local en ACCESS 97
    DoCmd.TransferDatabase acTable, "Bases de datos ODBC", _
"ODBC;DATABASE=<nombre de base de datos>;UID=<nombre de usuario>;PWD=<password>;DSN=<Creado en ODBC32>", _
          acTable, "Tmp_Dist", "T_COMPRAS"  
    bd.TableDefs.Refresh
    
' Borra la tabla auxiliar del servidor
    Set qdfTemp = conODBC.CreateQueryDef("")
    MiSQL = "if exists (select * from sysobjects where id = object_id('Tmp_ Dist') and sysstat & 0xf = 3)" & _
     " drop table Tmp_ Dist"
    With qdfTemp
        .Prepare = dbQUnprepare
        .SQL = MiSQL
        .ODBCTimeout = 120
        .Execute
    End With

    'Cierre de conexiones ODBC
    conODBC.Close : Set conODBC = nothing
    wsODBC.Close : Set wsODBC = nothing
    Set bd = Nothing
    Forms!T_COMPRAS!Lit_Estado.Caption = "Proceso finalizado"
    DoEvents
    DoCmd.SetWarnings True
    DoCmd.Hourglass False
    Forms!T_COMPRAS!Salir.SetFocus
End Sub

ir al índice