none
Campo de una u otra tabla RRS feed

  • Pregunta

  • Hola, tengo una consulta con respecto a una consulta en SQL.

    Mi duda es como puedo hacer para seleccionar un campo de una u otro tabla. Me trato de explicar un poco mejor, necesito seleccionar el valor de un campo en una u otra tabla dependiendo del valor de una tabla.

    En particular tengo una tabla llamada "CuentaCorriente" la cual tiene un campo llamado "FkPersona" el cual guarda PK de un cliente o un proveedor, y otro campo llamado "tipo" del tipo string que almacena si se trata de un "Proveedor" o "Cliente". Lo que trato de hacer el seleccionar el campo "nombre" a la cual corresponde la FK que esta en la tabla "CuentaCorriente", pero el problema me surge cuando tengo que determinar si va a buscarlo en la tabla "Clientes" o "Proveedor".

    ¿Como podria hacer para determinar en que tabla va a buscar el valor?

    Espero me puedan ayudar, gracias.

    lunes, 6 de agosto de 2018 13:48

Respuestas

  • Algo en contra de este esquema es que no se puede usar referencia declarativa para enforzar que la relacion exista durante la creacion.

    Otra forma seria creando una restriccion de valor por defecto y de chequeo en cada tabla, luego formar una vista de union de ambas tablas. Esto simplifica futuros queries entre ellas.

    CREATE TABLE dbo.cuentaCorriente
    (id        INT IDENTITY(1, 1),
     FkPersona INT,
     Cuenta    VARCHAR(28),
     tipo      VARCHAR(10) NOT NULL CHECK (tipo IN ('Cliente', 'Proveedor'))
    );
    GO
    CREATE TABLE dbo.cliente
    (id     INT,
     nombre VARCHAR(10),
     tipo AS 'Cliente' PERSISTED,
     CONSTRAINT chk_tipo_cliente CHECK (tipo = 'Cliente')
    );
    GO
    CREATE TABLE dbo.proveedor
    (id     INT,
     nombre VARCHAR(10),
     tipo AS 'Proveedor' PERSISTED,
     CONSTRAINT chk_tipo_proveedor CHECK (tipo = 'Proveedor')
    );
    GO
    INSERT INTO cuentaCorriente
    (FkPersona,
     Cuenta,
     tipo
    )
    VALUES
    (1,
     '0001',
     'cliente'
    ),
    (1,
     '0002',
     'proveedor'
    );
    GO
    INSERT INTO cliente
    (id,
     nombre
    )
    VALUES
    (1,
     'juanCli'
    ),
    (2,
     'Oscar'
    ),
    (3,
     'Luis'
    );
    INSERT INTO proveedor
    (id,
     nombre
    )
    VALUES
    (1,
     'juanPro'
    ),
    (2,
     'Manolo'
    );
    GO
    CREATE VIEW dbo.vw_ClienteProveedor
    WITH SCHEMABINDING
    AS
    SELECT id, nombre, tipo
    FROM dbo.cliente
    UNION ALL
    SELECT id, nombre, tipo
    FROM dbo.proveedor;
    GO
    SELECT *
    FROM cuentaCorriente c
         INNER JOIN
    	 dbo.vw_ClienteProveedor AS CP
    	 ON CP.id = c.id
    	 AND CP.tipo = C.tipo;


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    lunes, 6 de agosto de 2018 16:57
  • Si ambas tablas suelen tener el mismo tipo de data en la clave primaria entonces puedes crear una tercera tabla donde tengas las columnas comunes a ambas entidades.

    cliente-proveedor (supertipo) -> id, nombre, tipo ("Cliente", "Proveedor")
    cliente (subtipo) -> (id, tipo ("Cliente"), otras columnas de interes y no comunes)
    proveedor (subtipo) -> (id, tipo ("Proveedor"), otras columnas de interes y no comunes)

    Las tablas Cliente y Proveedor tendran una restriccion de clave foranea apuntando al supertipo (id, tipo) -> (id, tipo).


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    lunes, 6 de agosto de 2018 14:59
  • Hola Federico32113:

    Espero haber entendido bien tu escenario. Creo que es algo así:

    CREATE TABLE cuentaCorriente
    (id        INT IDENTITY(1, 1),
     FkPersona INT,
     Cuenta    VARCHAR(28),
     tipo      VARCHAR(10)
    );
    GO
    CREATE TABLE cliente
    (id     INT,
     nombre VARCHAR(10)
    );
    GO
    CREATE TABLE proveedor
    (id     INT,
     nombre VARCHAR(10)
    );
    GO
    INSERT INTO cuentaCorriente
    (FkPersona,
     Cuenta,
     tipo
    )
    VALUES
    (1,
     '0001',
     'cliente'
    ),
    (1,
     '0002',
     'proveedor'
    );
    GO
    INSERT INTO cliente
    (id,
     nombre
    )
    VALUES
    (1,
     'juanCli'
    ),
    (2,
     'Oscar'
    ),
    (3,
     'Luis'
    );
    INSERT INTO proveedor
    (id,
     nombre
    )
    VALUES
    (1,
     'juanPro'
    ),
    (2,
     'Manolo'
    );
    GO
    SELECT *
    FROM cuentaCorriente c
         LEFT JOIN cliente cli ON c.FkPersona = cli.id
                                  AND c.tipo = 'cliente'
         LEFT JOIN proveedor p ON c.FkPersona = p.id
                                  AND c.tipo = 'proveedor';
    

    En la propia relación puedes establecer el tipado.

    Un saludo

    lunes, 6 de agosto de 2018 15:06

Todas las respuestas

  • Si ambas tablas suelen tener el mismo tipo de data en la clave primaria entonces puedes crear una tercera tabla donde tengas las columnas comunes a ambas entidades.

    cliente-proveedor (supertipo) -> id, nombre, tipo ("Cliente", "Proveedor")
    cliente (subtipo) -> (id, tipo ("Cliente"), otras columnas de interes y no comunes)
    proveedor (subtipo) -> (id, tipo ("Proveedor"), otras columnas de interes y no comunes)

    Las tablas Cliente y Proveedor tendran una restriccion de clave foranea apuntando al supertipo (id, tipo) -> (id, tipo).


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    lunes, 6 de agosto de 2018 14:59
  • Hola Federico32113:

    Espero haber entendido bien tu escenario. Creo que es algo así:

    CREATE TABLE cuentaCorriente
    (id        INT IDENTITY(1, 1),
     FkPersona INT,
     Cuenta    VARCHAR(28),
     tipo      VARCHAR(10)
    );
    GO
    CREATE TABLE cliente
    (id     INT,
     nombre VARCHAR(10)
    );
    GO
    CREATE TABLE proveedor
    (id     INT,
     nombre VARCHAR(10)
    );
    GO
    INSERT INTO cuentaCorriente
    (FkPersona,
     Cuenta,
     tipo
    )
    VALUES
    (1,
     '0001',
     'cliente'
    ),
    (1,
     '0002',
     'proveedor'
    );
    GO
    INSERT INTO cliente
    (id,
     nombre
    )
    VALUES
    (1,
     'juanCli'
    ),
    (2,
     'Oscar'
    ),
    (3,
     'Luis'
    );
    INSERT INTO proveedor
    (id,
     nombre
    )
    VALUES
    (1,
     'juanPro'
    ),
    (2,
     'Manolo'
    );
    GO
    SELECT *
    FROM cuentaCorriente c
         LEFT JOIN cliente cli ON c.FkPersona = cli.id
                                  AND c.tipo = 'cliente'
         LEFT JOIN proveedor p ON c.FkPersona = p.id
                                  AND c.tipo = 'proveedor';
    

    En la propia relación puedes establecer el tipado.

    Un saludo

    lunes, 6 de agosto de 2018 15:06
  • Algo en contra de este esquema es que no se puede usar referencia declarativa para enforzar que la relacion exista durante la creacion.

    Otra forma seria creando una restriccion de valor por defecto y de chequeo en cada tabla, luego formar una vista de union de ambas tablas. Esto simplifica futuros queries entre ellas.

    CREATE TABLE dbo.cuentaCorriente
    (id        INT IDENTITY(1, 1),
     FkPersona INT,
     Cuenta    VARCHAR(28),
     tipo      VARCHAR(10) NOT NULL CHECK (tipo IN ('Cliente', 'Proveedor'))
    );
    GO
    CREATE TABLE dbo.cliente
    (id     INT,
     nombre VARCHAR(10),
     tipo AS 'Cliente' PERSISTED,
     CONSTRAINT chk_tipo_cliente CHECK (tipo = 'Cliente')
    );
    GO
    CREATE TABLE dbo.proveedor
    (id     INT,
     nombre VARCHAR(10),
     tipo AS 'Proveedor' PERSISTED,
     CONSTRAINT chk_tipo_proveedor CHECK (tipo = 'Proveedor')
    );
    GO
    INSERT INTO cuentaCorriente
    (FkPersona,
     Cuenta,
     tipo
    )
    VALUES
    (1,
     '0001',
     'cliente'
    ),
    (1,
     '0002',
     'proveedor'
    );
    GO
    INSERT INTO cliente
    (id,
     nombre
    )
    VALUES
    (1,
     'juanCli'
    ),
    (2,
     'Oscar'
    ),
    (3,
     'Luis'
    );
    INSERT INTO proveedor
    (id,
     nombre
    )
    VALUES
    (1,
     'juanPro'
    ),
    (2,
     'Manolo'
    );
    GO
    CREATE VIEW dbo.vw_ClienteProveedor
    WITH SCHEMABINDING
    AS
    SELECT id, nombre, tipo
    FROM dbo.cliente
    UNION ALL
    SELECT id, nombre, tipo
    FROM dbo.proveedor;
    GO
    SELECT *
    FROM cuentaCorriente c
         INNER JOIN
    	 dbo.vw_ClienteProveedor AS CP
    	 ON CP.id = c.id
    	 AND CP.tipo = C.tipo;


    AMB

    Some guidelines for posting questions...

    AYÚDANOS A AYUDARTE, guía básica de consejos para formular preguntas

    lunes, 6 de agosto de 2018 16:57
  • Gracias por la ayuda.

    Tengo una duda mas, seria conveniente si separo las CuentasCorrientes por "Proveedores" y "Clientes"(Creando 2 tablas diferentes) o mantener todos en una mejor?

    martes, 7 de agosto de 2018 19:42
  • Hola!

    Según he entendido tu problema y revisando tu última pregunta, lo normal sería mantener las CuentasCorrientes unidas, sin embargo "la división" que preguntas dependerá realmente de los requerimientos de tu proyecto, pero generalmente irían en la misma tabla.

    Saludos!


    Roberto Pozo (colocolino73)
    MVP SQL Server
    Blog: angaroasoft

    Please mark answered if I've answered your question and vote for it as helpful to help other user's find a solution quicker

    martes, 7 de agosto de 2018 21:01