none
Campos calculados Cross Apply RRS feed

  • Pregunta

  • Hola,

    En la siguiente consulta estoy tratando de obtener el dato del precio unitario de un movimiento de venta, ya que ese datos no se guarda en la BD.

    SELECT b.cFecha,b.cSerieDocumento,b.cFolio, 
    d.cCodigoAgente,d.cNombreAgente,
    a.cIdProducto,c.cCodigoProducto,c.cNombreProducto,
    a.cUnidades, a.cNeto, ca1.nDescuento, ca2.nTotal, 
    CAST( ( ca2.nTotal / a.cUnidades) AS DECIMAL(18,2) ) AS nPrecioUnitario
    FROM admMovimientos AS a INNER JOIN admDocumentos AS b ON b.cIdDocumento=a.cIdDocumento
    INNER JOIN admProductos AS c ON c.cIdProducto=a.cIdProducto
    INNER JOIN admAgentes AS d ON d.cIdAgente=b.cIdAgente
    Cross Apply ( SELECT a.cDescuento1 + a.cDescuento2 + 
    a.cDescuento3 + a.cDescuento4 + a.cDescuento5 AS nDescuento ) ca1
    CROSS APPLY ( SELECT a.cNeto - ca1.nDescuento AS nTotal ) ca2
    WHERE b.cIdDocumentoDe IN (4) AND b.cFecha BETWEEN '20181001' AND '20181001' AND b.cCancelado=0 ORDER BY b.cFecha, b.cFolio

    La consulta funciona correctamente pero no estoy seguro si estoy haciendo lo correcto utilizando Cross Apply, es decir, lo intenté con una subconsulta y no obtuve los resultados deseados.

    Si es mejor una subconsulta por favor me pueden dar una idea como generar la consulta.

    Gracias.

    Javier


    • Editado jparada martes, 11 de diciembre de 2018 2:13
    martes, 11 de diciembre de 2018 2:13

Respuestas

  • Hola:

    En la primera opción la columna se llama

    WHERE b.admDocumentos = a.admDocumentos

    es

    WHERE b.cidDocumentos = a.cidDocumentos

    Y en la segunda casi igual

    AS ca1 ON ca1.admDocumentos = a.admDocumentos

    debe decir

    AS ca1 ON ca1.cidDocumentos = a.cidDocumentos

    Opción 3, tal y como te índica el moderador, con toda la razón.

    SELECT b.cFecha,
           b.cSerieDocumento,
           b.cFolio,
           d.cCodigoAgente,
           d.cNombreAgente,
           a.cIdProducto,
           c.cCodigoProducto,
           c.cNombreProducto,
           a.cUnidades,
           a.cNeto,
           ( a.cDescuento1 + a.cDescuento2 + a.cDescuento3 + a.cDescuento4 + a.cDescuento5) AS nDescuento
           (a.cNeto - ( a.cDescuento1 + a.cDescuento2 + a.cDescuento3 + a.cDescuento4 + a.cDescuento5)) as Neto,
           CAST(((a.cNeto - ( a.cDescuento1 + a.cDescuento2 + a.cDescuento3 + a.cDescuento4 + a.cDescuento5)) / a.cUnidades) AS DECIMAL(18, 2)) AS nPrecioUnitario
    FROM admMovimientos AS a
         INNER JOIN admDocumentos AS b ON b.cIdDocumento = a.cIdDocumento
         INNER JOIN admProductos AS c ON c.cIdProducto = a.cIdProducto
         INNER JOIN admAgentes AS d ON d.cIdAgente = b.cIdAgente
         
    WHERE b.cIdDocumentoDe IN(4)
         AND b.cFecha BETWEEN '20181001' AND '20181001'
         AND b.cCancelado = 0
    ORDER BY b.cFecha,
             b.cFolio;

    Espero te ayude


    miércoles, 12 de diciembre de 2018 5:31

Todas las respuestas

  • Hola jparada:

    Yo te diría que no.

    SELECT b.cFecha,
           b.cSerieDocumento,
           b.cFolio,
           d.cCodigoAgente,
           d.cNombreAgente,
           a.cIdProducto,
           c.cCodigoProducto,
           c.cNombreProducto,
           a.cUnidades,
           a.cNeto,
           ca1.nDescuento,
           ca1.nTotal,
           CAST(((a.c.Neto - ca1.nDescuento) / a.cUnidades) AS DECIMAL(18, 2)) AS nPrecioUnitario
    FROM admMovimientos AS a
         INNER JOIN admDocumentos AS b ON b.cIdDocumento = a.cIdDocumento
         INNER JOIN admProductos AS c ON c.cIdProducto = a.cIdProducto
         INNER JOIN admAgentes AS d ON d.cIdAgente = b.cIdAgente
         CROSS APPLY
    (
        SELECT b.cDescuento1 + b.cDescuento2 + b.cDescuento3 + b.cDescuento4 + b.cDescuento5 AS nDescuento
               
        FROM admMovimientos b
        WHERE b.admDocumentos = a.admDocumentos
              AND b.cIdProducto = a.cidProducto
    ) ca1
    WHERE b.cIdDocumentoDe IN(4)
         AND b.cFecha BETWEEN '20181001' AND '20181001'
         AND b.cCancelado = 0
    ORDER BY b.cfecha,
             b.cFolio;
    /* Tabla derivada */
    SELECT b.cFecha,
           b.cSerieDocumento,
           b.cFolio,
           d.cCodigoAgente,
           d.cNombreAgente,
           a.cIdProducto,
           c.cCodigoProducto,
           c.cNombreProducto,
           a.cUnidades,
           a.cNeto,
           ca1.nDescuento,
           ca1.nTotal,
           CAST(((a.cNeto - ca1.nDescuento) / a.cUnidades) AS DECIMAL(18, 2)) AS nPrecioUnitario
    FROM admMovimientos AS a
         INNER JOIN admDocumentos AS b ON b.cIdDocumento = a.cIdDocumento
         INNER JOIN admProductos AS c ON c.cIdProducto = a.cIdProducto
         INNER JOIN admAgentes AS d ON d.cIdAgente = b.cIdAgente
         INNER JOIN
    (
        SELECT b.admDocumentos,
               b.cidProducto,
               b.cDescuento1 + b.cDescuento2 + b.cDescuento3 + b.cDescuento4 + b.cDescuento5 AS nDescuento
        FROM admMovimientos b
    ) AS ca1 ON ca1.admDocumentos = a.admDocumentos
                AND ca1.cIdProducto = a.cidProducto
    WHERE b.cIdDocumentoDe IN(4)
         AND b.cFecha BETWEEN '20181001' AND '20181001'
         AND b.cCancelado = 0
    ORDER BY b.cfecha,
             b.cFolio;
    

    Te he puesto dos opciones, por si te ayudan.

    martes, 11 de diciembre de 2018 6:35
  • lo que yo me pregunto es para que necesitas un corss apply si lo que estas haciendo es simplemente un campo calculado, podrías poner lo mismo que pones en el cross apply como campo calculado. 

    No le veo sentido a usar cross apply, mucho menos poniendo el from  a modo subconsulta porque realmente estarías volviendo a leer la tabla sin necesidad alguna (aunque igual lo arregle el plan de ejecución)

    En resumen, saca eso y conviértelo en campos calculados  o déjalo estar si funciona, (creo que SQL lo ejecutará de la misma manera).



    Comparte lo que sepas, aprende lo que no sepas (FGG)
    portalSQL
    El rincón del DBA

    • Propuesto como respuesta Pedro Alfaro martes, 11 de diciembre de 2018 15:50
    martes, 11 de diciembre de 2018 7:52
    Moderador
  • Hola Javi,

    La primer opción despliega errores:

    Mens. 207, Nivel 16, Estado 1, Línea 23
    El nombre de columna 'admDocumentos' no es válido.
    Mens. 207, Nivel 16, Estado 1, Línea 23
    El nombre de columna 'admDocumentos' no es válido.
    Mens. 207, Nivel 16, Estado 1, Línea 12
    El nombre de columna 'nTotal' no es válido.
    Mens. 207, Nivel 16, Estado 1, Línea 13
    El nombre de columna 'c' no es válido.

    La segunda opción también:

    Mens. 207, Nivel 16, Estado 1, Línea 21
    El nombre de columna 'admDocumentos' no es válido.
    Mens. 207, Nivel 16, Estado 1, Línea 25
    El nombre de columna 'admDocumentos' no es válido.
    Mens. 207, Nivel 16, Estado 1, Línea 13
    El nombre de columna 'nTotal' no es válido.

    Saludos,

    Javier

    miércoles, 12 de diciembre de 2018 3:00
  • Hola:

    En la primera opción la columna se llama

    WHERE b.admDocumentos = a.admDocumentos

    es

    WHERE b.cidDocumentos = a.cidDocumentos

    Y en la segunda casi igual

    AS ca1 ON ca1.admDocumentos = a.admDocumentos

    debe decir

    AS ca1 ON ca1.cidDocumentos = a.cidDocumentos

    Opción 3, tal y como te índica el moderador, con toda la razón.

    SELECT b.cFecha,
           b.cSerieDocumento,
           b.cFolio,
           d.cCodigoAgente,
           d.cNombreAgente,
           a.cIdProducto,
           c.cCodigoProducto,
           c.cNombreProducto,
           a.cUnidades,
           a.cNeto,
           ( a.cDescuento1 + a.cDescuento2 + a.cDescuento3 + a.cDescuento4 + a.cDescuento5) AS nDescuento
           (a.cNeto - ( a.cDescuento1 + a.cDescuento2 + a.cDescuento3 + a.cDescuento4 + a.cDescuento5)) as Neto,
           CAST(((a.cNeto - ( a.cDescuento1 + a.cDescuento2 + a.cDescuento3 + a.cDescuento4 + a.cDescuento5)) / a.cUnidades) AS DECIMAL(18, 2)) AS nPrecioUnitario
    FROM admMovimientos AS a
         INNER JOIN admDocumentos AS b ON b.cIdDocumento = a.cIdDocumento
         INNER JOIN admProductos AS c ON c.cIdProducto = a.cIdProducto
         INNER JOIN admAgentes AS d ON d.cIdAgente = b.cIdAgente
         
    WHERE b.cIdDocumentoDe IN(4)
         AND b.cFecha BETWEEN '20181001' AND '20181001'
         AND b.cCancelado = 0
    ORDER BY b.cFecha,
             b.cFolio;

    Espero te ayude


    miércoles, 12 de diciembre de 2018 5:31
  • Hola Javi,

    Gracias por el ejemplo funcionó perfecto!!!.

    Gracias a todos.

    Saludos,

    Javier

    jueves, 13 de diciembre de 2018 17:43
  • De nada
    jueves, 13 de diciembre de 2018 21:05