Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   SQL (https://www.clubdelphi.com/foros/forumdisplay.php?f=6)
-   -   Esta subconsulta puede devolver como máximo un registro (https://www.clubdelphi.com/foros/showthread.php?t=63646)

salvica 24-02-2009 19:15:58

Esta subconsulta puede devolver como máximo un registro
 
Hola a tod@s, de nuevo por estos lares :D:D:D

Código:

Tabla CONTRATOS
===============
      ID_Clave ------> el identificador del contrato
      ID_Inquilino --> el identificador del inquilino (inquilino.ID_CLAVE)
      ID_Propiedad --> el identificador de la propiedad (propiedad.ID_CLAVE)
      ID_Propietario > el identificador del propietario de la propiedad

Tabla INQUILINO
===============
      ID_Clave ------> el identificador del inquilino
      ...

Tabla PROPIEDAD
===============
      ID_Clave ------> el identificador de la propiedad
      TIPO ----------> el tipo de propiedad (vivienda, garaje, comercial, etc)
      ...

Se trata de sacar TODOS los INQUILINOS con el tipo de propiedades alquiladas, o en blanco si no tiene ninguna.

Inicialmente habia probado con esto:
Código SQL [-]
SELECT inquilin.ID_CLAVE,
       inquilin.NOMBRE, inquilin.APELLIDO_1, inquilin.APELLIDO_2,
       inquilin.NIF,
       inquilin.TELEFONO_1,
       inquilin.DIRECCION, inquilin.LOCALIDAD,
      (SELECT propieda.TIPO
         FROM contrato, propieda
        WHERE contrato.ID_INQUILI=inquilin.ID_CLAVE
          AND contrato.ID_PROPIED=propieda.ID_CLAVE
      ) AS alquilado
  FROM inquilin
 ORDER BY inquilin.APELLIDO_1, inquilin.APELLIDO_2, inquilin.NOMBRE
pero no vale, ya que puede haber (y de hecho los hay) inquilinos con varias propiedades alquiladas, mensaje de error: Esta subconsulta puede devolver como máximo un registro
Gracias adelantadas
salvica

ContraVeneno 24-02-2009 19:29:19

Código SQL [-]
Select A.Campo, B.Campo
From TablaA A
left outer join TablaB B On A.ID = B.ID

eso te regresa todos los registros de A y te muestra las ocurrencias en la tabla B, si no hay ninguna, muestra "NULL"

Kipow 24-02-2009 19:54:13

Por ahi andaria.

Código SQL [-]
select A.ID_CLAVE AS INQUILINO, C.ID_CLAVE AS PROPIEDAD
FROM (INQUILINO A LEFT OUTER JOIN CONTRATOS B ON A.ID_CLAVE = B.ID_INQUILINO) INNER JOIN PROPIEDAD C ON B.ID_CLAVE = 
C.ID_CLAVE

Ahora bien el problema que te esta dando seguramente es porque estas asignando esos valores luego de la consulta con el INTO. si sabes que puede devolver mas de 1 registro no puedes hacerlo asi. debes hacerlo por medio de un cursor.

salvica 24-02-2009 20:02:28

Cita:

Empezado por ContraVeneno (Mensaje 339191)
Código SQL [-]Select A.Campo, B.Campo From TablaA A left outer join TablaB B On A.ID = B.ID


eso te regresa todos los registros de A y te muestra las ocurrencias en la tabla B, si no hay ninguna, muestra "NULL"

Hola ContraVeneno, gracias por responder, he hecho esto:
Código SQL [-]
         SQL.Add( 'SELECT inquilin.ID_CLAVE,' );
         SQL.Add( '       inquilin.NOMBRE, inquilin.APELLIDO_1, inquilin.APELLIDO_2, inquilin.NIF,' );
         SQL.Add( '       inquilin.TELEFONO_1, inquilin.DIRECCION, inquilin.LOCALIDAD,' );
         SQL.Add( '      (SELECT propieda.TIPO' );
         SQL.Add( '         FROM propieda' );
         SQL.Add( '              LEFT OUTER JOIN contrato' );
         SQL.Add( '                ON contrato.ID_INQUILI=propieda.ID_CLAVE' );
         SQL.Add( '      ) AS alquilado' );
         SQL.Add( '  FROM inquilin' );
         SQL.Add( ' ORDER BY inquilin.APELLIDO_1, inquilin.APELLIDO_2, inquilin.NOMBRE' );
y me sigue dando el mismo error :mad:
salvica

Kipow 24-02-2009 20:13:55

ya vi tu problema, el problema esta en la consulta anidada,
Código SQL [-]
 SQL.Add( '      (SELECT propieda.TIPO' );
         SQL.Add( '         FROM propieda' );
         SQL.Add( '              LEFT OUTER JOIN contrato' );
         SQL.Add( '                ON contrato.ID_INQUILI=propieda.ID_CLAVE' );
         SQL.Add( '      ) AS alquilado' );



Porque?, porque esa subconsulta solo debe de devolver un valor y como lo estas haciendo te esta devolviendo en algunos
casos varios valores, proba como te lo coloque yo.

Saludos.

salvica 24-02-2009 20:26:17

Cita:

Empezado por Kipow (Mensaje 339195)
Por ahi andaria.

Código SQL [-]select A.ID_CLAVE AS INQUILINO, C.ID_CLAVE AS PROPIEDAD FROM (INQUILINO A LEFT OUTER JOIN CONTRATOS B ON A.ID_CLAVE = B.ID_INQUILINO) INNER JOIN PROPIEDAD C ON B.ID_CLAVE = C.ID_CLAVE


Hola Kipow, he probado tu consulta y ebtengo el error La expresión de combinación no está admitida

Pensé que era más fácil y no lo puse :mad:, utilizo ADO y según "Inner Join" no permite anidar "Left Join" en su interior

salvica 24-02-2009 20:30:02

No edito el anterior porque se "descabala" todo

Es al revés :D un Left Join no admite anidar Inner Join en su interior

salvica 24-02-2009 20:47:56

Según eso, lo he puesto así:
Código SQL [-]
         SQL.Add( 'SELECT inquilin.ID_CLAVE,' );
         SQL.Add( '       inquilin.NOMBRE, inquilin.APELLIDO_1, inquilin.APELLIDO_2,' );
         SQL.Add( '       inquilin.NIF,' );
         SQL.Add( '       inquilin.TELEFONO_1, inquilin.DIRECCION, inquilin.LOCALIDAD,' );
         SQL.Add( '       propieda.TIPO' );
         SQL.Add( '  FROM inquilin' );
         SQL.Add( '       INNER JOIN (contrato' );
         SQL.Add( '                   LEFT JOIN propieda' );
         SQL.Add( '                      ON contrato.ID_PROPIED=propieda.ID_CLAVE' );
         SQL.Add( '       ) ON inquilin.ID_CLAVE=contrato.ID_INQUILI' );
         SQL.Add( ' ORDER BY inquilin.APELLIDO_1, inquilin.APELLIDO_2, inquilin.NOMBRE' );
pero no me dá los inquilinos que no tienen propiedades alquiladas (posibles inquilinos a hacerles un contrato)
¿ideas?
salvica

duilioisola 24-02-2009 21:30:38

Creo que la solución es esta:

Cita:

Se trata de sacar TODOS los INQUILINOS con el tipo de propiedades alquiladas, o en blanco si no tiene ninguna.
Código SQL [-]
SELECT inquilino.ID_CLAVE,
       inquilino.NOMBRE, inquilino.APELLIDO_1, inquilino.APELLIDO_2,
       inquilino.NIF,
       inquilino.TELEFONO_1,
       inquilino.DIRECCION, inquilino.LOCALIDAD,propiedad.TIPO
FROM INQUILINO
LEFT JOIN CONTRATOS
on inquilino.ID_Clave=CONTRATOS.ID_Inquilino
LEFT JOIN PROPIEDAD
on CONTRATOS.ID_Propiedad=PROPIEDAD.ID_Clave

WHERE PROPIEDAD.TIPO=:TIPO

ORDER BY inquilino.APELLIDO_1, inquilino.APELLIDO_2, inquilino.NOMBRE

Debes utilizar el LEFT JOIN, pues quieres todo lo que esté en la tabla de la izquierda de la relación, sin importar que haya o no datos en la tabla de la derecha de relación.
Qudaría:
Todos los Inquilinos.
De estos todos sus contratos, si las hubiera.
De estos todas sus propiedades, si las hubiera.

salvica 24-02-2009 22:23:50

Cita:

Empezado por duilioisola (Mensaje 339212)
Creo que la solución es esta:
Debes utilizar el LEFT JOIN, pues quieres todo lo que esté en la tabla de la izquierda de la relación, sin importar que haya o no datos en la tabla de la derecha de relación.
Qudaría:
Todos los Inquilinos.
De estos todos sus contratos, si las hubiera.
De estos todas sus propiedades, si las hubiera.

Hola duilioisola, gracias, funciona a la perfección. He tenido que adaptarlo al sql de ado y queda así:
Código SQL [-]
         SQL.Clear;
         SQL.Add( 'SELECT inquilin.ID_CLAVE,' );
         SQL.Add( '       inquilin.NOMBRE, inquilin.APELLIDO_1, inquilin.APELLIDO_2,' );
         SQL.Add( '       inquilin.NIF,' );
         SQL.Add( '       inquilin.TELEFONO_1,' );
         SQL.Add( '       inquilin.DIRECCION, inquilin.LOCALIDAD,' );
         SQL.Add( '       propieda.TIPO' );
         SQL.Add( '  FROM inquilin' );
         SQL.Add( '       LEFT JOIN (contrato' );
         SQL.Add( '                  LEFT JOIN propieda' );
         SQL.Add( '                    ON contrato.ID_PROPIED=propieda.ID_CLAVE' );
         SQL.Add( '       ) ON inquilin.ID_CLAVE=contrato.ID_INQUILI' );
         SQL.Add( ' ORDER BY inquilin.APELLIDO_1, inquilin.APELLIDO_2, inquilin.NOMBRE' );
Por cierto, esto para qué era?
Código SQL [-]
         SQL.Add( ' WHERE propieda.TIPO=:TIPO' );
Gracias a tod@s por la ayuda prestada
Salvica

duilioisola 25-02-2009 00:02:51

Cita:

Se trata de sacar TODOS los INQUILINOS con el tipo de propiedades alquiladas, o en blanco si no tiene ninguna
.
El where es para hacer un filtro. Por lo que explicabas, pensé que querías un tipo determinado de propiedad.
De todos modos, y ahora que lo pienso un poco mejor, si quisieras, por ejemplo solo garages, deberías poner algo así:
Código Delphi [-]
   [...]
   SQL.Add( ' WHERE (propieda.TIPO=:TIPO or propieda.TIPO is null)' );
   SQL.Add( ' ORDER BY inquilin.APELLIDO_1, inquilin.APELLIDO_2, inquilin.NOMBRE' );
   Params.ByName['TIPO'].AsString := 'GARAGE';
   [...]


La franja horaria es GMT +2. Ahora son las 23:52:06.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi