none
Modelo de base de datos para sistema de inventario de ropas y zapatos RRS feed

  • Pregunta

  • Hola

    Estoy trabajando en un sistema de inventario para una web deportiva. Van haber muchos tipos de productos dentro los cuales quiero destacar:

    • Suplementos deportivos.
    • Zapatos.

    Hasta el momento este es mi modelo:


    Tengo los siguientes registros:

    INSERT INTO Production.ProductBase (ProductBaseID, Name) VALUES (1, 'Whey Protein')
    INSERT INTO Production.Product (ProductID, Model, ProductBaseID) VALUES (1, 'Chocolate', 1)
    INSERT INTO Production.Product (ProductID, Model, ProductBaseID) VALUES (2, 'Vainilla', 1)
    
    INSERT INTO Production.ProductBase (ProductBaseID, Name) VALUES (2, 'Air Max')
    INSERT INTO Production.Product (ProductID, Model, ProductBaseID) VALUES (3, 'Rojos', 2)
    INSERT INTO Production.ProductAttribute (ProductID, ProductAttribute) VALUES (3, 'Talla 10')
    INSERT INTO Production.ProductAttribute (ProductID, ProductAttribute) VALUES (3, 'Talla 11')
    
    INSERT INTO Production.Product (ProductID, Model, ProductBaseID) VALUES (4, 'Blancos', 2)
    INSERT INTO Production.ProductAttribute (ProductID, ProductAttribute) VALUES (4, 'Talla 8')

    Para explicarlo un poco tengo suplementos "Whey Protein" pueden ser de chocolate o Vainilla. Tengo Zapatos de un modelo específico, el color puede ser rojo o blanco y estos tienen tallas.

    El problema lo tengo con la tabla ProductInventory ya que las cantidades no están relacionadas a los atributos, que en el caso de los zapatos serían las tallas. Pensaba agregarle la columna ProductAttribute a esa tabla y crear un primary key conjunto ProductID y ProductAttributeID), sin embargo no todos los productos tienen atributos.

    Alguna idea para mejorar mi modelo?

    Adjunto scripts:

    CREATE TABLE [Production].[ProductBase](
    	[ProductBaseID] [int] IDENTITY(1,1) NOT NULL,
    	[Name] [dbo].[Name] NOT NULL,
    	[ProductCategoryID] [int] NULL,
    	[ModifiedDate] [datetime] NOT NULL,
    	CONSTRAINT [PK_ProductBase_ProductBaseID] PRIMARY KEY CLUSTERED ([ProductBaseID] ASC)
    ) ON [PRIMARY]
    GO
    CREATE TABLE [Production].[Product](
    	[ProductID] [int] IDENTITY(1,1) NOT NULL,
    	[ProductBaseID] [int] NOT NULL,
    	[ModelTypeID] [int] NOT NULL,
    	[Model] [dbo].[Name] NOT NULL,
    	[ListPrice] [money] NOT NULL,
    	[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_Product_ModifiedDate] DEFAULT getdate(),
    	CONSTRAINT [PK_Product_ProductID] PRIMARY KEY CLUSTERED ([ProductID] ASC)
    )
    GO
    CREATE TABLE [Production].[ProductAttribute](
    	[ProductAttributeID] [int] IDENTITY(1,1) NOT NULL,
    	[ProductID] [int] NOT NULL,
    	[ProductAttributeTypeID] [int] NOT NULL,
    	[ProductAttribute] [dbo].[Name] NOT NULL,
    	[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_ProductAttribute_ModifiedDate] DEFAULT getdate(),
    	CONSTRAINT [PK_ProductAttribute_ProductAttributeId] PRIMARY KEY CLUSTERED ([ProductAttributeID] ASC)
    )
    GO
    CREATE TABLE [Production].[ProductInventory](
    	[ProductID] [int] NOT NULL,
    	[ProductAttributeID] [int] NULL,
    	[Quantity] [smallint] NOT NULL CONSTRAINT [DF_ProductInventory_Quantity]  DEFAULT ((0)),
    	[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_ProductInventory_ModifiedDate]  DEFAULT getdate(),
    	CONSTRAINT [PK_ProductInventory_ProductID_LocationID] PRIMARY KEY CLUSTERED ([ProductID] ASC)
    )
    GO

    Muchas gracias

    sábado, 12 de septiembre de 2020 3:47

Respuestas

  • Hola Adylr:

    Aunque no estoy de acuerdo con el extendido modelo de que los productos tienen una tabla stock, ya que desde mi impresión esto es algo incorrecto, porque el stock, lo producen los movimientos (compras, ventas etc) sobre estos productos, no obstante, la solución más obvia, es crear la tabla de Production.ProductInventory con una clave subrogada

    https://bmegias.wordpress.com/2011/01/31/%C2%BFclaves-primarias-naturales-o-subrogadas/

    Y añadir foreign keys hacia las tablas.

    CREATE TABLE [ProductInventory](
    	[ProductInventoryID] INT IDENTITY(1,1) PRIMARY KEY,
    	[ProductID] [int] NOT NULL,
    	[ProductAttributeID] [int] NULL,
    	[Quantity] [smallint] NOT NULL CONSTRAINT [DF_ProductInventory_Quantity]  DEFAULT ((0)),
    	[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_ProductInventory_ModifiedDate]  DEFAULT getdate(),
    	CONSTRAINT [PK_ProductInventory_Product] FOREIGN KEY ([ProductID]) REFERENCES [Product] (PRODUCTID),
    	CONSTRAINT [PK_ProductInventory_ProductAttribute] FOREIGN KEY ([ProductID]) REFERENCES [ProductAttribute] ([ProductAttributeID])
    )
    GO

    Esto te permite Insertar los null para column ProductAttributeId

    INSERT INTO [ProductInventory] ([ProductID],[ProductAttributeID],[Quantity],[ModifiedDate])
    VALUES
    (1,NULL,5,GETDATE()),
    (3,1,5,GETDATE()),
    (3,2,5,GETDATE()),
    (2,NULL,5,GETDATE());

    • Marcado como respuesta AdyIr sábado, 26 de septiembre de 2020 1:35
    sábado, 12 de septiembre de 2020 5:40

Todas las respuestas

  • Hola Adylr:

    Aunque no estoy de acuerdo con el extendido modelo de que los productos tienen una tabla stock, ya que desde mi impresión esto es algo incorrecto, porque el stock, lo producen los movimientos (compras, ventas etc) sobre estos productos, no obstante, la solución más obvia, es crear la tabla de Production.ProductInventory con una clave subrogada

    https://bmegias.wordpress.com/2011/01/31/%C2%BFclaves-primarias-naturales-o-subrogadas/

    Y añadir foreign keys hacia las tablas.

    CREATE TABLE [ProductInventory](
    	[ProductInventoryID] INT IDENTITY(1,1) PRIMARY KEY,
    	[ProductID] [int] NOT NULL,
    	[ProductAttributeID] [int] NULL,
    	[Quantity] [smallint] NOT NULL CONSTRAINT [DF_ProductInventory_Quantity]  DEFAULT ((0)),
    	[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_ProductInventory_ModifiedDate]  DEFAULT getdate(),
    	CONSTRAINT [PK_ProductInventory_Product] FOREIGN KEY ([ProductID]) REFERENCES [Product] (PRODUCTID),
    	CONSTRAINT [PK_ProductInventory_ProductAttribute] FOREIGN KEY ([ProductID]) REFERENCES [ProductAttribute] ([ProductAttributeID])
    )
    GO

    Esto te permite Insertar los null para column ProductAttributeId

    INSERT INTO [ProductInventory] ([ProductID],[ProductAttributeID],[Quantity],[ModifiedDate])
    VALUES
    (1,NULL,5,GETDATE()),
    (3,1,5,GETDATE()),
    (3,2,5,GETDATE()),
    (2,NULL,5,GETDATE());

    • Marcado como respuesta AdyIr sábado, 26 de septiembre de 2020 1:35
    sábado, 12 de septiembre de 2020 5:40
  • Hola Adylr:

    Aunque no estoy de acuerdo con el extendido modelo de que los productos tienen una tabla stock, ya que desde mi impresión esto es algo incorrecto, porque el stock, lo producen los movimientos (compras, ventas etc) sobre estos productos, no obstante, la solución más obvia, es crear la tabla de Production.ProductInventory con una clave subrogada

    https://bmegias.wordpress.com/2011/01/31/%C2%BFclaves-primarias-naturales-o-subrogadas/

    Y añadir foreign keys hacia las tablas.

    CREATE TABLE [ProductInventory](
    	[ProductInventoryID] INT IDENTITY(1,1) PRIMARY KEY,
    	[ProductID] [int] NOT NULL,
    	[ProductAttributeID] [int] NULL,
    	[Quantity] [smallint] NOT NULL CONSTRAINT [DF_ProductInventory_Quantity]  DEFAULT ((0)),
    	[ModifiedDate] [datetime] NOT NULL CONSTRAINT [DF_ProductInventory_ModifiedDate]  DEFAULT getdate(),
    	CONSTRAINT [PK_ProductInventory_Product] FOREIGN KEY ([ProductID]) REFERENCES [Product] (PRODUCTID),
    	CONSTRAINT [PK_ProductInventory_ProductAttribute] FOREIGN KEY ([ProductID]) REFERENCES [ProductAttribute] ([ProductAttributeID])
    )
    GO

    Esto te permite Insertar los null para column ProductAttributeId

    INSERT INTO [ProductInventory] ([ProductID],[ProductAttributeID],[Quantity],[ModifiedDate])
    VALUES
    (1,NULL,5,GETDATE()),
    (3,1,5,GETDATE()),
    (3,2,5,GETDATE()),
    (2,NULL,5,GETDATE());

    Hola Javier

    Muchas gracias por tu observación, es válida y estoy abierto a cambiar el modelo. En lo personal nunca he trabajado con sistemas de inventarios. Tomando tu recomendación, me imagino algo así:

    Donde las tablas SalesOrderDetail y PurchaseOrderDetail tienen un ProductID y ProductAttributeID (nullable).  Creo que sería bueno crear algún flag o indicador que diga si un producto es obligatorio que tenga un Atributo. De esta forma no podría agregar un registro en la tabla Purchase por ejemplo de un Zapato, sin haber indicado la talla.

    Sin embargo la pregunta sería. EL saber las cantidades de un producto desde las distintas aplicaciones, será una función común... Cuando el usuario busque un producto, cuando vea el detalle, en caso que sea un producto con atributos como tallas debo saber por cada talla si hay o no disponibilidad, etc...

    ¿No va afectar en redimiento hacer constantemente COUNT sobre las tablas Sales y Purchase? Tienes alguna sugerencia al respecto?

    Gracias nuevamente.

    domingo, 13 de septiembre de 2020 13:15
  • Hola Adylr:

    De esta forma no podría agregar un registro en la tabla Purchase por ejemplo de un Zapato, sin haber indicado la talla.

    Puede ser, no obstante eso depende un poco de la lógica de negocio que quieras implementar. 

    Si es peor en rendimiento, realizar cálculos, que leer de una tabla. Bueno eso depende de muchos factores, pero esto si lo realizas bien en una vista, cuya query esté bien optimizada, merece la pena, porque jamás tendrás fallos de stock, y realmente, lo que realizas es una query sobre un producto. La cual realmente va a realizar búsquedas en un árbol indizado.

    Además cambiar de modelo de si tienes la aplicación montada y todos los puntos consulta el stock sobre una vista, y cuando ya tienes millones de registros, ves que en alguno te empieza a contar realizar una función Sum() sobre los movimientos que conlleva, y quieres cambiar al modelo de la tabla, solo tienes que crear la tabla con la salida de los datos que te devuelve la vista, y como el nombre es el mismo, la aplicación no se enterará. O los cambios son tan superfluos que no importa.

    En cuanto a soluciones, si empeorase el rendimiento, hay varias, desde utilizar vistas indexadas, indices particionados y otras. Pero eso es un paso al cual no tienes porque llegar. Y conllevaría, que tendrías que tener muchos, pero muchos registros de salesOrdersDetail y purchaseOrdersDetail, para un product específico.

     


    domingo, 13 de septiembre de 2020 15:03