none
Sub Consulta que genera mas de un registro RRS feed

  • Pregunta

  • Hola buenas tardes, como solucionaría esta situación, estoy realizando una subconsulta, pero generas más de un registro y al parecer la subconsulta no puede devolver más de  un row, que se puede hacer en ese caso, les coloco mi query:

    SELECT        A.IdAprobacionCal, A.IdClienteProveedor, CASE WHEN C.NombreCliente IS NULL THEN D .NombreProveedor ELSE C.NombreCliente END AS NombreClienteProveedor, A.IdTransporte, E.NombreTransporte, A.IdVehiculo, 
                             F.Vehiculo, A.IdChofer, B.NombreChofer, A.OC, A.PesoOC, A.FechaHoraIngCal, A.UsuarioIngCal, CASE WHEN A.AprobacionEliminada = 1 THEN 'Sí' ELSE 'No' END AS Eliminado,A.ObserAprobIngCal,A.ObserAprobDespCal,(SELECT T_MetodoEnsayo.DesMetodoEnsayo FROM   T_AprobacionCalMetodoEnsayo INNER JOIN
                             T_Tickets ON T_AprobacionCalMetodoEnsayo.IdAprobacionCal = T_Tickets.IdAprobacionCal INNER JOIN
                             T_MetodoEnsayo ON T_AprobacionCalMetodoEnsayo.IdMetodoEnsayo = T_MetodoEnsayo.IdMetodoEnsayo
    WHERE        (T_Tickets.IdAprobacionCal = 'APRR-0000006114')) AS MetodosEnsayos
    FROM            dbo.T_Tickets AS A INNER JOIN
                             dbo.T_Choferes AS B ON A.IdChofer = B.IdChofer LEFT OUTER JOIN
                             dbo.T_Clientes AS C ON A.IdClienteProveedor = C.IdCliente LEFT OUTER JOIN
                             dbo.T_Proveedores AS D ON A.IdClienteProveedor = D.Idproveedor INNER JOIN
                             dbo.T_Transportes AS E ON A.IdTransporte = E.IdTransporte INNER JOIN
                             dbo.T_Vehiculos AS F ON A.IdVehiculo = F.IdVehiculo

    cuando lo corro, me sale esto en la consola de SQL Server:

    Msg 512, Level 16, State 1, Line 32
    Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

     

    MetodosEnsayos me debería traer varios registros.<o:p></o:p>

    <o:p> </o:p>

    Espero me puedan apoyar.<o:p></o:p>

    miércoles, 28 de agosto de 2019 20:21

Todas las respuestas

  • Hola Vladimir Angarita:

    Si tu idea es que solo traiga un registro, la solución más simple pasa por usar el operador TOP.

    SELECT A.IdAprobacionCal, 
           A.IdClienteProveedor,
           CASE
               WHEN C.NombreCliente IS NULL
               THEN D.NombreProveedor
               ELSE C.NombreCliente
           END AS NombreClienteProveedor, 
           A.IdTransporte, 
           E.NombreTransporte, 
           A.IdVehiculo, 
           F.Vehiculo, 
           A.IdChofer, 
           B.NombreChofer, 
           A.OC, 
           A.PesoOC, 
           A.FechaHoraIngCal, 
           A.UsuarioIngCal,
           CASE
               WHEN A.AprobacionEliminada = 1
               THEN 'Sí'
               ELSE 'No'
           END AS Eliminado, 
           A.ObserAprobIngCal, 
           A.ObserAprobDespCal, 
    (
        SELECT top(1) T_MetodoEnsayo.DesMetodoEnsayo
        FROM T_AprobacionCalMetodoEnsayo
             INNER JOIN T_Tickets ON T_AprobacionCalMetodoEnsayo.IdAprobacionCal = T_Tickets.IdAprobacionCal
             INNER JOIN T_MetodoEnsayo ON T_AprobacionCalMetodoEnsayo.IdMetodoEnsayo = T_MetodoEnsayo.IdMetodoEnsayo
        WHERE(T_Tickets.IdAprobacionCal = 'APRR-0000006114') 
        ORDER BY T_MetodoEnsayo.DesMetodoEnsayo
    ) AS MetodosEnsayos
    FROM dbo.T_Tickets AS A
         INNER JOIN dbo.T_Choferes AS B ON A.IdChofer = B.IdChofer
         LEFT OUTER JOIN dbo.T_Clientes AS C ON A.IdClienteProveedor = C.IdCliente
         LEFT OUTER JOIN dbo.T_Proveedores AS D ON A.IdClienteProveedor = D.Idproveedor
         INNER JOIN dbo.T_Transportes AS E ON A.IdTransporte = E.IdTransporte
         INNER JOIN dbo.T_Vehiculos AS F ON A.IdVehiculo = F.IdVehiculo;
    Si tu idea es la contraria, dinóslo, para cambiar esa subquery por el operador apply, u otro modo de obtener lo que deseas

    jueves, 29 de agosto de 2019 3:53
  • Hola buenos días, gracias por responder, ¿Si tu idea es que solo traiga un registro, la solución más simple pasa por usar el operador TOP? No mi pana!, lo que busco es que muestre el listado de MetodosyEnsayos, como podiria hacer eso??
    jueves, 29 de agosto de 2019 11:53
  • Hola:

    Si pero eso que significa, ya que existen muchas maneras de entender eso.

    Row1, col1, col2, col3, metodosYEnsayos.

    1 , 1, 1, 1, Metodo1

    1 , 1, 1, 1, Metodo2

    1 , 1, 1, 1, Metodo3

    2 , 1, 1, 1, null

    3 , 1, 1, 1, Metodo1

    4 , 1, 1, 1, Metodo1

    O significa

    Row1, col1, col2, col3, metodosYEnsayos.

    1 , 1, 1, 1, Metodo1;Metodo2;Metodo3;

    2 , 1, 1, 1, null

    3 , 1, 1, 1, Metodo1

    4 , 1, 1, 1, Metodo1

    Y la segunda pregunta es Version del motor Sql server

    jueves, 29 de agosto de 2019 12:05
  • Hola buenos días, la version del SQL Server, es 
    jueves, 29 de agosto de 2019 12:09
  • Podrias colocar un ejemplito, por favor :-)
    jueves, 29 de agosto de 2019 12:13
  • El ejemplito era:

    Row1, col1, col2, col3, metodosYEnsayos.

    1 , 1, 1, 1, Metodo1

    1 , 1, 1, 1, Metodo2

    1 , 1, 1, 1, Metodo3

    2 , 1, 1, 1, null

    3 , 1, 1, 1, Metodo1

    4 , 1, 1, 1, Metodo1

    Donde row1, es la fila 1 actual, más cada una de las columnas que tu tienes.

    Si la subconsulta devuelve 3 valores, que se hace????, se repiten las 3 filas.

    O se concatenan en una sola columna???

    jueves, 29 de agosto de 2019 13:04
  • Si la Sub consulta devuelve 3 valores, esos valores son distintos, ya que es el detalle de la cabecera que representa la consulta principal!
    jueves, 29 de agosto de 2019 13:35
  • primero que nada una disculpa por meterme en este post busco ayuda sobre este tema https://social.msdn.microsoft.com/Forums/en-US/8eab0829-2d58-41ee-a719-6d886f34283e/promedio-y-sumatoria-sql-server?forum=sqlserveres agradeciera si me pudieran ayudar
    jueves, 29 de agosto de 2019 15:17
  • Eso es muy cierto. Pero tu estas solicitando una consulta. No 1 y 3 como presentarías en un formulario.

    Piensa que lo que te devuelva la consulta, no es más un datatable, o datagrid o una serie de filas de una hoja de Excel.

    Por tanto ya que la fila de la cabecera tiene que contener los registros del detalle, como se devuelve la consulta, repitiendo por cada uno de los del detalle, todos los valores de la cabecera.

    IdAprobacionCal = 1 , IdClienteProveedor = 3 …. metodosYEnsayos = Metodo1 (como el detalle tiene tres valores...repito fila)

    IdAprobacionCal = 1 , IdClienteProveedor = 3 …. metodosYEnsayos = Metodo2 

    IdAprobacionCal = 1 , IdClienteProveedor = 3 …. metodosYEnsayos = Metodo3

    IdAprobacionCal = 2 , IdClienteProveedor = 21 …. metodosYEnsayos = null

    Esto es una pobilidad.

    La otra, es que para la columna metodosYEnsayos, todos los valores del detalle, se concatenen en esa celda.

    Espero haber sido más claro. 

    jueves, 29 de agosto de 2019 15:20
  • estimado javi fernandez, busco ayuda https://social.msdn.microsoft.com/Forums/en-US/8eab0829-2d58-41ee-a719-6d886f34283e/promedio-y-sumatoria-sql-server?forum=sqlserveres orientacion como ya sabes soy novato en esto me podrias ayudar y una disculpa enorme por hacer esto de esta manera
    jueves, 29 de agosto de 2019 15:28
  • Oye no te entendi bien, colocare el Procedimiento de almacenado completo, colocando las variables parametros!:

    SELECT        A.IdAprobacionCal, A.IdClienteProveedor, CASE WHEN C.NombreCliente IS NULL THEN D .NombreProveedor ELSE C.NombreCliente END AS NombreClienteProveedor, A.IdTransporte, E.NombreTransporte, A.IdVehiculo, 
                             F.Vehiculo, A.IdChofer, B.NombreChofer, A.OC, A.PesoOC, A.FechaHoraIngCal, A.UsuarioIngCal, CASE WHEN A.AprobacionEliminada = 1 THEN 'Sí' ELSE 'No' END AS Eliminado,A.ObserAprobIngCal,A.ObserAprobDespCal,(SELECT Top 1 T_MetodoEnsayo.DesMetodoEnsayo FROM   T_AprobacionCalMetodoEnsayo INNER JOIN
                             T_Tickets ON T_AprobacionCalMetodoEnsayo.IdAprobacionCal = T_Tickets.IdAprobacionCal INNER JOIN
                             T_MetodoEnsayo ON T_AprobacionCalMetodoEnsayo.IdMetodoEnsayo = T_MetodoEnsayo.IdMetodoEnsayo
    WHERE        (T_Tickets.IdAprobacionCal = @IdAprobacionCal)) AS MetodosEnsayos
    FROM            dbo.T_Tickets AS A INNER JOIN
                             dbo.T_Choferes AS B ON A.IdChofer = B.IdChofer LEFT OUTER JOIN
                             dbo.T_Clientes AS C ON A.IdClienteProveedor = C.IdCliente LEFT OUTER JOIN
                             dbo.T_Proveedores AS D ON A.IdClienteProveedor = D.Idproveedor INNER JOIN
                             dbo.T_Transportes AS E ON A.IdTransporte = E.IdTransporte INNER JOIN
                             dbo.T_Vehiculos AS F ON A.IdVehiculo = F.IdVehiculo
    WHERE  A.IdCompania = @IdComp 
    and (@IdAprobacionCal is null or a.IdAprobacionCal like @IdAprobacionCal)

    Como puedes apreciar es una consulta cabecera detalle donde el IdAprobacionCal que esta en la tabla T_Ticket (tabla a) esta en una tabla T_AprobacionCalMetodoEnsayo alli estan los detalles!, efectivamente, es una consulta lo que estoy realizando, pero hay un campo que me tiene un detalle osea varios  rows que debo de alguna manera concatenar!

    jueves, 29 de agosto de 2019 15:35
  • Hola Vladimir Angarita:

    Tu escenario:

    Create table T_Tickets(IdAprobacionCal varchar(20),IdClienteProveedor int,IdTransporte int, IdVehiculo int, idChofer int,OC int, PesoOc int, FechaHoraIngCal datetime,UsuarioIngCal int,
    AprobacionEliminada int,ObserAprobIngCal varchar(100), ObserAprobDespCal varchar(100), IdCompania int)
    Create Table T_Choferes (IdChofer int, NombreChofer varchar(100))
    Create Table T_Clientes (IdCliente int, NombreCliente varchar(100))
    Create Table T_Proveedores (IdProveedor int, NombreProveedor varchar(100))
    Create Table T_Transportes(idTransporte int, NombreTransporte varchar(100))
    Create Table T_Vehiculos(idVehiculo int, Vehiculo varchar(100))
    Create Table T_AprobacionCalMetodoEnsayo (IdAprobacionCal varchar(100),idMetodoEnsayo int)
    Create Table T_MetodoEnsayo (IdMetodoEnsayo int, DesMetodoEnsayo varchar(100))
    go
    /* Maestro 2 rows*/
    Insert into T_Tickets(IdAprobacionCal,IdClienteProveedor,IdTransporte, IdVehiculo, idChofer,OC, PesoOc, FechaHoraIngCal,UsuarioIngCal,
    AprobacionEliminada,ObserAprobIngCal, ObserAprobDespCal, IdCompania)
    Values
    ('APRR-0000006114', 1, 100, 200, 5, 10,14, '20190101',1, 1, 'ObserAprog Ing', 'ObserDes',1000),
    ('APRR-0000006115', 2, 100, 200, 5, 10,14, '20190101',1, 1, 'ObserAprog Ing', 'ObserDes',1000);
    /* Chofer */
    Insert into T_Choferes (IdChofer, NombreChofer)
    values
    (5,'Ana Perez'),
    (6,'Sebas Rodriguez');
    /* Clientes */
    Insert into T_Clientes(IdCliente, NombreCliente)
    values (1,'Oscar'),(3,'Roberto');
    /* Proveedores */
    Insert into T_Proveedores (IdProveedor, NombreProveedor)
    values
    (2,'Prov NOm');
    /* Transportes */
    insert into T_Transportes (idTransporte, NombreTransporte)
    values
    (100, 'Trasnportes Perez');
    /* Vehiculos */
    Insert into T_Vehiculos (idVehiculo, Vehiculo)
    values
    (200, 'Mercedes benz 904 2003 04 cilindros modelo 2000');
    /* detalle */
    Insert into T_AprobacionCalMetodoEnsayo (IdAprobacionCal, idMetodoEnsayo)
    values
    ('APRR-0000006114',1),
    ('APRR-0000006114',2),
    ('APRR-0000006114',3),
    ('APRR-0000006115',4),
    ('APRR-0000006115',5);
    /* Ensayo */
    Insert into T_MetodoEnsayo(IdMetodoEnsayo, DesMetodoEnsayo)
    values 
    (1,'Ensayo 1'),
    (2,'Ensayo 2'),
    (3,'Ensayo 3'),
    (4,'Ensayo 4'),
    (5,'Ensayo 5');
    
    

    Los tipos de datos, e incluso los valores pueden no encajar del todo, pero las columnas son las mismas que muestras.

    SELECT A.IdAprobacionCal, 
           A.IdClienteProveedor,
           CASE
               WHEN C.NombreCliente IS NULL
               THEN D.NombreProveedor
               ELSE C.NombreCliente
           END AS NombreClienteProveedor, 
           A.IdTransporte, 
           E.NombreTransporte, 
           A.IdVehiculo, 
           F.Vehiculo, 
           A.IdChofer, 
           B.NombreChofer, 
           A.OC, 
           A.PesoOC, 
           A.FechaHoraIngCal, 
           A.UsuarioIngCal,
           CASE
               WHEN A.AprobacionEliminada = 1
               THEN 'Sí'
               ELSE 'No'
           END AS Eliminado, 
           A.ObserAprobIngCal, 
           A.ObserAprobDespCal, 
    (
        SELECT TOP 1 T_MetodoEnsayo.DesMetodoEnsayo
        FROM T_AprobacionCalMetodoEnsayo
             INNER JOIN T_Tickets ON T_AprobacionCalMetodoEnsayo.IdAprobacionCal = T_Tickets.IdAprobacionCal
             INNER JOIN T_MetodoEnsayo ON T_AprobacionCalMetodoEnsayo.IdMetodoEnsayo = T_MetodoEnsayo.IdMetodoEnsayo
       -- WHERE(T_Tickets.IdAprobacionCal = @IdAprobacionCal)
    ) AS MetodosEnsayos
    FROM dbo.T_Tickets AS A
         INNER JOIN dbo.T_Choferes AS B ON A.IdChofer = B.IdChofer
         INNER JOIN dbo.T_Transportes AS E ON A.IdTransporte = E.IdTransporte
         INNER JOIN dbo.T_Vehiculos AS F ON A.IdVehiculo = F.IdVehiculo
         LEFT OUTER JOIN dbo.T_Clientes AS C ON A.IdClienteProveedor = C.IdCliente
         LEFT OUTER JOIN dbo.T_Proveedores AS D ON A.IdClienteProveedor = D.Idproveedor
    
         

    Observa que te he quitado los where, porque yo no tengo datos, pero te he reordenado los conjuntos. Primero inner join, después left outer join.

    Salida

    Es evidente que hay más columnas, pero para el ejemplo son suficientes.

    Una posible solución con repetición de filas. Operador Outer apply

    SELECT A.IdAprobacionCal, 
           A.IdClienteProveedor,
           CASE
               WHEN C.NombreCliente IS NULL
               THEN D.NombreProveedor
               ELSE C.NombreCliente
           END AS NombreClienteProveedor, 
           A.IdTransporte, 
           E.NombreTransporte, 
           A.IdVehiculo, 
           F.Vehiculo, 
           A.IdChofer, 
           B.NombreChofer, 
           A.OC, 
           A.PesoOC, 
           A.FechaHoraIngCal, 
           A.UsuarioIngCal,
           CASE
               WHEN A.AprobacionEliminada = 1
               THEN 'Sí'
               ELSE 'No'
           END AS Eliminado, 
           A.ObserAprobIngCal, 
           A.ObserAprobDespCal, 
    	  MetodosEnsayos.DesMetodoEnsayo
    
    FROM dbo.T_Tickets AS A
         INNER JOIN dbo.T_Choferes AS B ON A.IdChofer = B.IdChofer
         INNER JOIN dbo.T_Transportes AS E ON A.IdTransporte = E.IdTransporte
         INNER JOIN dbo.T_Vehiculos AS F ON A.IdVehiculo = F.IdVehiculo
         LEFT OUTER JOIN dbo.T_Clientes AS C ON A.IdClienteProveedor = C.IdCliente
         LEFT OUTER JOIN dbo.T_Proveedores AS D ON A.IdClienteProveedor = D.Idproveedor
    	outer apply
    	(
        SELECT  T_MetodoEnsayo.DesMetodoEnsayo
        FROM T_AprobacionCalMetodoEnsayo TA
             INNER JOIN T_Tickets ON TA.IdAprobacionCal = T_Tickets.IdAprobacionCal
             INNER JOIN T_MetodoEnsayo ON TA.IdMetodoEnsayo = T_MetodoEnsayo.IdMetodoEnsayo
           WHERE A.IdAprobacionCal = TA.IdAprobacionCal
    ) AS MetodosEnsayos
         

    Observa que el conjunto llamado MetodosEnsayos, referencia al conjunto exterior llamado de alias A en el where

    Salida

    Esta es la solución más lógica para un maestro detalle, devolviendo en una sola Sentencia SQL.

    ¿Es esto lo que necesitas?

    jueves, 29 de agosto de 2019 19:44