none
Consultar tablas temporales

    Pregunta

  • Buenas tardes, para reducir recursos y tiempos de espera a la hora de ejecutar una consulta al sql server 2008  desde mi aplicación de escritorio vb.net he pensado en crear tablas temporales.

    Desde el management studio las creo y pruebo:

    SELECT *INTO #TablaTemporal FROM linea1 where TipoHorario = 'laborables' 
    select * from #TablaTemporarl  where ID > 10

    Funciona correctamente,

    Ejecutándola desde vb.net no hay manera.....


            dbConexion.Open()
            Dim datemporal As New OleDbDataAdapter("SELECT *INTO #TablaTemporal FROM linea1 where TipoHorario = 'laborables' select * from  #TablaTemporal where ID > 10", connStringOLEDB)
            Dim dt As New DataTable
            datemporal.Fill(dt)
    
            dgdiferencias.DataSource = dt
            dbConexion.Close()


    forlanfor

    lunes, 6 de febrero de 2017 17:22

Respuestas

  • "Forlanfor" escribió:

    > Desde el management studio las creo y pruebo:
    >
    > SELECT *INTO #TablaTemporal FROM linea1 where TipoHorario = 'laborables'
    > select * from #TablaTemporarl  where ID > 10
    >
    > Funciona correctamente,
    >
    > Ejecutándola desde vb.net no hay manera.....
    >
    > Dim datemporal As New OleDbDataAdapter("SELECT *INTO #TablaTemporal FROM linea1
    > where TipoHorario = 'laborables' select * from  #TablaTemporal where ID > 10", connStringOLEDB)
    >
    > Dim dt As New DataTable
    > datemporal.Fill(dt)

    Hola:

    Es que la consulta SQL que le estás indicando al objeto OleDbDataAdapter no es del todo correcta, al menos para dicho objeto, porque éste no sabe si tiene que crear la tabla temporal con los datos de la tabla linea1 (SELECT * INTO) o tiene que seleccionar los datos de la tabla temporal, en definitiva, que desconoce si tiene que ejecutar una consulta de acción, de selección o ambas juntas. Otra cuestión diferente es lo que tu puedas ejecutar desde el propio Administrador de SQL Server.

    Desde tu aplicación de .NET, tendrías que ejecutar por un lado la consulta SQL de acción (SELECT * INTO), y por otro, seleccionar los datos propiamente dichos:

    Imports System.Data.OleDb
    
       Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using dbConexion As New OleDbConnection(connStringOLEDB)
                    dbConexion.Open()
                    Dim cmd As OleDbCommand = dbConexion.CreateCommand()
    
                    ' Primero crear la tabla temporal con los datos de la tabla linea1
                    cmd.CommandText = "SELECT * INTO #TablaTemporal FROM linea1 WHERE TipoHorario = 'laborables'" 
                    cmd.ExecuteNonQuery()
    
                    ' Después seleccionar los datos de la tabla temporal
                    cmd.CommandText = "SELECT * FROM #TablaTemporal WHERE ID > 10"
                    Dim datemporal As New OleDbDataAdapter(cmd)
                    Dim dt As New DataTable()
                    datemporal.Fill(dt)
    
                    dgdiferencias.DataSource = dt
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    En cambio, si utilizaras el propio proveedor de datos .NET para SQL Server, en lugar de su proveedor de datos OleDb (que es lo que hay que hacer si se va a trabajar con SQL Server desde una aplicación .NET), entonces sí podrías ejecutarlo todo en un único comando, sin necesidad de abrir y cerrar explícitamente la conexión, ya que de ello se encargará el adaptador de datos utilizado:

    Imports System.Data.SqlClient
    
       Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using dbConexion As New SqlConnection(connStringOLEDB)
    
                    ' Abrir la conexión
                    ' dbConexion.Open() --> NO ES NECESARIO
    
                    ' Crear un comando
                    Dim cmd As SqlCommand = dbConexion.CreateCommand()
    
                    cmd.CommandText = "SELECT * INTO #TablaTemporal FROM linea1 WHERE TipoHorario = 'laborables' SELECT * FROM #TablaTemporal WHERE ID > 10"
                    Dim datemporal As New SqlDataAdapter(cmd)
                    Dim dt As New DataTable()
                    datemporal.Fill(dt)
    
                    dgdiferencias.DataSource = dt
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Digo que no es necesario abrir explícitamente la conexión porque la segunda consulta que se va a ejecutar es una consulta SQL de selección. Si hubiera que ejecutar una única consulta de acción (INSERT INTO, SELECT * INTO, UPDATE, DELETE, etc.), entonces sí hay que abrir explícitamente la conexión, ya que en éste caso no se utiliza para ello un adaptador de datos (un objeto SqlDataAdapter).

    Te comento que utilizando el proveedor de datos .NET para SQL Server, en la cadena de conexión NO PUEDE aparecer el parámetro Provider, por tanto, tienes que eliminarlo de la cadena de conexión.

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    lunes, 6 de febrero de 2017 17:59
    Moderador
  • Forlanfor,

    ¿Que versión del motor de SQL Server ocupas?. Lo pregunto porque es válido usar el proveedor de datos OleDb sólo si estuvieses usando una versión 6.5 o anterior (hablamos de una versión lanzada hace 20 años). Si ocupas una versión 7.0 o superior lo adecuado es que uses el proveedor de datos SqlClient que es el proveedor de datos ad-hoc "directo y sin escalas" para SQL Server en el marco de trabajo de .Net.

    Pero vamos a tomar por un momento el proveedor OleDb para ver lo que está sucediendo. Al ejecutar la consulta sql que adjuntas se producen dos resultados, el primer resultado es la cuenta de las filas afectadas por la operación de inserción y la segunda es el conjunto de resultados propio de la consulta de selección, ¿y cómo solucionamos eso?, pues podríamos hacer uso de la instrucción SET NOCOUNT para evitar el primer resultado y obtener el que nos interesa.

    OleDbDataAdapter("SET NOCOUNT ON; SELECT * INTO <...> ; SELECT * FROM <...>;", ...)

    El código anterior es sólo para demostrar como podrías obtener los resultados que esperas pero -reitero- que lo adecuado es que ocupes el proveedor SqlClient entendiendo que no ocupas una versión de SQL Server de hace 20 años. Claro, el proveedor SqlClient expone sus propias clases: SqlConnection, SqlCommand, SqlDataAdapter, etc.

    Finalmente, ¿qué ahorro de "recursos" intentas evitar con la consulta que realizas? discúlpame pero yo no lo veo a menos que hayas escrito una consulta cualquiera como ejemplo, lo que escribes es simple y performante hacerlo de la siguiente manera:

    SELECT * FROM linea1 WHERE ID > 10 AND TipoHorario = 'laborables';
    GO

    Se entiende que la columna [ID] tiene un índice clustered, si resulta lento deberías ver la posibilidad de crear un índice compuesto por ambas columnas.



    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta Forlanfor martes, 7 de febrero de 2017 4:42
    lunes, 6 de febrero de 2017 18:40

Todas las respuestas

  • Hola ,si estás usando sql deberías usar los objetos de ADO.NET pata esta BD

    SqlDataAdapter


    Si la respuesta te fue útil vótala como tal,y si fue respuesta márcala. Solo dejo en el foro mis post si fueron útiles , de lo contrario y por mantener el orden los borro. Saludos. Lima-Perú.

    lunes, 6 de febrero de 2017 17:26
  • "Forlanfor" escribió:

    > Desde el management studio las creo y pruebo:
    >
    > SELECT *INTO #TablaTemporal FROM linea1 where TipoHorario = 'laborables'
    > select * from #TablaTemporarl  where ID > 10
    >
    > Funciona correctamente,
    >
    > Ejecutándola desde vb.net no hay manera.....
    >
    > Dim datemporal As New OleDbDataAdapter("SELECT *INTO #TablaTemporal FROM linea1
    > where TipoHorario = 'laborables' select * from  #TablaTemporal where ID > 10", connStringOLEDB)
    >
    > Dim dt As New DataTable
    > datemporal.Fill(dt)

    Hola:

    Es que la consulta SQL que le estás indicando al objeto OleDbDataAdapter no es del todo correcta, al menos para dicho objeto, porque éste no sabe si tiene que crear la tabla temporal con los datos de la tabla linea1 (SELECT * INTO) o tiene que seleccionar los datos de la tabla temporal, en definitiva, que desconoce si tiene que ejecutar una consulta de acción, de selección o ambas juntas. Otra cuestión diferente es lo que tu puedas ejecutar desde el propio Administrador de SQL Server.

    Desde tu aplicación de .NET, tendrías que ejecutar por un lado la consulta SQL de acción (SELECT * INTO), y por otro, seleccionar los datos propiamente dichos:

    Imports System.Data.OleDb
    
       Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using dbConexion As New OleDbConnection(connStringOLEDB)
                    dbConexion.Open()
                    Dim cmd As OleDbCommand = dbConexion.CreateCommand()
    
                    ' Primero crear la tabla temporal con los datos de la tabla linea1
                    cmd.CommandText = "SELECT * INTO #TablaTemporal FROM linea1 WHERE TipoHorario = 'laborables'" 
                    cmd.ExecuteNonQuery()
    
                    ' Después seleccionar los datos de la tabla temporal
                    cmd.CommandText = "SELECT * FROM #TablaTemporal WHERE ID > 10"
                    Dim datemporal As New OleDbDataAdapter(cmd)
                    Dim dt As New DataTable()
                    datemporal.Fill(dt)
    
                    dgdiferencias.DataSource = dt
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    En cambio, si utilizaras el propio proveedor de datos .NET para SQL Server, en lugar de su proveedor de datos OleDb (que es lo que hay que hacer si se va a trabajar con SQL Server desde una aplicación .NET), entonces sí podrías ejecutarlo todo en un único comando, sin necesidad de abrir y cerrar explícitamente la conexión, ya que de ello se encargará el adaptador de datos utilizado:

    Imports System.Data.SqlClient
    
       Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Try
                Using dbConexion As New SqlConnection(connStringOLEDB)
    
                    ' Abrir la conexión
                    ' dbConexion.Open() --> NO ES NECESARIO
    
                    ' Crear un comando
                    Dim cmd As SqlCommand = dbConexion.CreateCommand()
    
                    cmd.CommandText = "SELECT * INTO #TablaTemporal FROM linea1 WHERE TipoHorario = 'laborables' SELECT * FROM #TablaTemporal WHERE ID > 10"
                    Dim datemporal As New SqlDataAdapter(cmd)
                    Dim dt As New DataTable()
                    datemporal.Fill(dt)
    
                    dgdiferencias.DataSource = dt
                End Using
    
            Catch ex As Exception
                MessageBox.Show(ex.Message)
    
            End Try
    
        End Sub

    Digo que no es necesario abrir explícitamente la conexión porque la segunda consulta que se va a ejecutar es una consulta SQL de selección. Si hubiera que ejecutar una única consulta de acción (INSERT INTO, SELECT * INTO, UPDATE, DELETE, etc.), entonces sí hay que abrir explícitamente la conexión, ya que en éste caso no se utiliza para ello un adaptador de datos (un objeto SqlDataAdapter).

    Te comento que utilizando el proveedor de datos .NET para SQL Server, en la cadena de conexión NO PUEDE aparecer el parámetro Provider, por tanto, tienes que eliminarlo de la cadena de conexión.

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.




    lunes, 6 de febrero de 2017 17:59
    Moderador
  • Forlanfor,

    ¿Que versión del motor de SQL Server ocupas?. Lo pregunto porque es válido usar el proveedor de datos OleDb sólo si estuvieses usando una versión 6.5 o anterior (hablamos de una versión lanzada hace 20 años). Si ocupas una versión 7.0 o superior lo adecuado es que uses el proveedor de datos SqlClient que es el proveedor de datos ad-hoc "directo y sin escalas" para SQL Server en el marco de trabajo de .Net.

    Pero vamos a tomar por un momento el proveedor OleDb para ver lo que está sucediendo. Al ejecutar la consulta sql que adjuntas se producen dos resultados, el primer resultado es la cuenta de las filas afectadas por la operación de inserción y la segunda es el conjunto de resultados propio de la consulta de selección, ¿y cómo solucionamos eso?, pues podríamos hacer uso de la instrucción SET NOCOUNT para evitar el primer resultado y obtener el que nos interesa.

    OleDbDataAdapter("SET NOCOUNT ON; SELECT * INTO <...> ; SELECT * FROM <...>;", ...)

    El código anterior es sólo para demostrar como podrías obtener los resultados que esperas pero -reitero- que lo adecuado es que ocupes el proveedor SqlClient entendiendo que no ocupas una versión de SQL Server de hace 20 años. Claro, el proveedor SqlClient expone sus propias clases: SqlConnection, SqlCommand, SqlDataAdapter, etc.

    Finalmente, ¿qué ahorro de "recursos" intentas evitar con la consulta que realizas? discúlpame pero yo no lo veo a menos que hayas escrito una consulta cualquiera como ejemplo, lo que escribes es simple y performante hacerlo de la siguiente manera:

    SELECT * FROM linea1 WHERE ID > 10 AND TipoHorario = 'laborables';
    GO

    Se entiende que la columna [ID] tiene un índice clustered, si resulta lento deberías ver la posibilidad de crear un índice compuesto por ambas columnas.



    Espero que la información proporcionada te haya sido de utilidad, quedo atento a tus comentarios.
    • Marcado como respuesta Forlanfor martes, 7 de febrero de 2017 4:42
    lunes, 6 de febrero de 2017 18:40
  • Gracias a todos muy buenas explicaciones. La escusa que tengo para utilizar el oldb es por que tengo algunas consultas a bd de access e importaciones al sqlserver,    tendré que acostumbrarme a utulizar sql y dejar el oldb solamente para el access.

    La verdad que no sabia que haba diferencia.

    César


    forlanfor

    martes, 7 de febrero de 2017 4:42
  • Gracias Willams, Sí la consulta es de prueba.

    El sql server es del 2008, la bd express. entiendo que tendre que utilizar al sqlclient

    César


    forlanfor

    martes, 7 de febrero de 2017 4:45