I have a table "AvailableProducts" with following fields:
StoreID int,
ProductID int,
ProductPrice decimal,
IsAvailable bit
The ProductPrice can be changed either by sales person in the store or it can be updated by a price update from the brand.
Now to store the history of price changes, I've created a history table as follows:
Table ProductPriceHistory
UpdateID int,
StoreID int,
ProductID int,
ProductPrice decimal,
IsAvailable bit,
UpdatedBy int,
UpdatedAt datetime
The problem I am facing is that keeping BrandID or SalesPersonID (That made the changes to price) in the UpdatedBy field is wrong design.
I can modify it to something like this:
Table ProductPriceHistory
UpdateID int,
StoreID int,
ProductID int,
ProductPrice decimal,
IsAvailable bit,
BrandId int,
SalesPersonID int,
UpdatedAt datetime
This would allow me to reference the updating entity by a foreign key in the Brand and SalesPerson Tables using the Id fields. But it would also lead to many empty or null column values since only one entity i.e. either brand or SalesPerson can update the price at given time.
I could also create two different history tables to save updates made by SalesPerson and Brands separately but this solution doesn't look appealing.
Any suggestions for improvement in this design as I would like the history for this table to be maintained in a single table. Thanks :)
You could create an ObjectType table with 2 items:
CREATE TABLE [dbo].[ObjectType](
[ObjectTypeId] [int] NOT NULL,
[ObjectTypeName] [nvarchar](100) NULL)
GO
INSERT INTO dbo.ObjectType VALUES (1, 'Brand')
INSERT INTO dbo.ObjectType VALUES (2, 'SalesPerson')
Then add a new column ObjectTypeId to table ProductPriceHistory
ALTER TABLE ProductPriceHistory
ADD ObjectTypeId int
You could write log for many kinds of item not only for SalesPerson and Brands
This is a common question - it's often asked in relation to the object orientation concept of polymorphism.
There are 3 standard solutions - you've identified two of them; the final one is to model the common fields in a single table, and have separate tables for the variant data. That would have tables "sales_update" and "brand_update", with foreign keys on updateID back to the update history table.
There is no elegant solution - the relational model simply doesn't support this use case particularly nicely. You need to look at the rest of your system, and pick the solution that's easiest in your case. Usually, that's the "one table stores everything model" - but your situation may be different.
Related
I'm a bit of an SQL novice, so please bear with me on this one. My project is as follows:
Using MSSQL on Windows Server 2008 R2.
There is an existing database table - let's call it PRODUCTS - which contains several thousand rows of data, which is the product information for every product Company X sells. The three columns I am interested in are ITEMGROUPID, ITEMID and ITEMNAME. The ITEMID is the primary key for this table, and is a unique product code. ITEMGROUPID indicates what category of product each item falls into, and ITEMNAME is self explanatory. I am only interested in one category of product, so by using ITEMGROUPID I can determine how many rows my table will have (currently 260).
I am now creating a table containing some parameters for making each of these products - let's call it LINEPARAMETERS. For example, when we make Widget A, we need Conveyor B to run at Speed C. I intend to create a foreign key in my table, pointing to the ITEMID in the other table. So each row in my new table will reference a specific product in the existing product database.
My question is, if a new product is developed that matches my criteria (ITEMGROUPID = 'VALUE'), and entered into the existing table with an ITEMID, is there any way for my table to automatically generate a new row with that ITEMID and default values in all other columns?
You could create a trigger that fires on insert to product and inserts a row into the lineparameters, like this:
create trigger line_parameter_inserter
on products
after insert
as
insert into lineparameters (productId, col1, col2)
values (inserted.id, 'foo', 'bar');
but a better option is to create a foreign key from the product table to your group defaults table, that way a row must exist in the defaults table before you insert the product table, like this:
create table lineparameters (
id int,
col1 int,
...,
primary key (id)
)
create table products (
id int,
lineparametersId int not null,
...
primary key (id),
foreign key (lineparametersId) references lineparameters(id)
)
This will create a solid process and ensures that even if someone (silently) disables/deletes the trigger, you won't have data integrity problems.
I am doing an order food online. But I am wondering if I can have 2 values in a same column. Or is there any way I can do something like that?
The DB structure:
id | product_code | product_name | price
Sample data:
1 | 'A01' | 'Chicken Fired Rice' | 6.50 10.50
So let say the chicken fried rice has two sizes regular for $6.50 and large for $10.50. Is there any idea how I can create a DB like this?
Thank you.
It's bad idea, your db design violates the first normal form: https://en.wikipedia.org/wiki/First_normal_form.
With this violation it will be much harder to write select against such table.
Don't store information like that in price column it violates the First Normal Form, It will be difficult to parse the data
I will go with two tables
One to store the product information and another table to store the price.
Product table
Create table Product
(
Product_Id int, --Auto generated
product_code varchar(10),
product_name varchar(100)
)
Price Table
Create table Price
(
Price_Id Int, --Auto Generated
Product_Id int, --Foreign key column referred from product table
Size varchar(20),
Price Decimal(10,2)
)
or If it is always two size then you can create single table with two column's to store Price of Regular and Large size.
Create table Product
(
Product_Id int, --Auto generated
product_code varchar(10),
product_name varchar(100),
Regular_size_price Decimal(10,2),
Large_size_price Decimal(10,2)
)
That is bad design from a DB perspective. To help you avoiding problems like this, there are a set of rules call Normal Forms.
There are many ways to work around this problem.
One is to add another column to your table "size" for example and insert to rows one for a small and another for large.
In case you really want to use that design, I'm sure you could same a String with comma separated values and pipes and use to creativity to break this String to size prices. :)
There are several ways; one is using a JSON field, something that's not universally supported. Though this is not a good idea in most situations, including yours.
Normalization is the process of breaking your database structures into logical relational parts (tables). For example:
Products: id | code | name
Prices: product_id | size | price
This way you can have any number of prices for any given product; product_id is a foreign key, a reference to the id field of a product. There's certainly other information that could/should/will be added to such a table structure, but this is the basis of the sort of flexibility you're asking for.
I am trying to understand the concept of an Analysis Services Cube. Please see the DLL below (Dim is short for Dimension):
CREATE TABLE DIMCustomer (ID INT identity, Name varchar(100), primary key (ID))
CREATE TABLE DIMSupplier (ID INT identity, Name varchar(100), primary key (ID))
CREATE TABLE DIMSalesman (ID INT identity, Name varchar(100), primary key (ID))
CREATE TABLE DIMDeliveryDriver (ID INT identity, Name varchar(100), primary key (ID))
CREATE TABLE DIMDate (ID INT identity, month varchar(100), day varchar(100), year varchar(100), primary key (ID))
CREATE TABLE FactTable (CustomerID int, SupplierID INT, SalesmanID INT, DeliveryDriverID int, DateID INT)
Is this an example of scenario that supports a five dimensional cube? (because the fact table contains five foreign keys (CustomerID, SupplierID, SalesmanID and DeliveryDriverID).
An OLAP cube is a technology that stores data in an optimized way to provide a quick response to various types of complex queries by using dimensions and measures.
OLAP cubes can be considered as the final piece of the puzzle for a data warehousing solution. The useful feature of an OLAP cube is that the data in the cube can be contained in an aggregated form.
In your case if you can include sales amount in facts table, it is possible to create sales summary handled by customer, supplier, salesman, delivery driver etc.
Suggest to read this for beginner level understanding with a sample:
https://www.codeproject.com/Articles/658912/Create-First-OLAP-Cube-in-SQL-Server-Analysis-Serv
You'd get a count measure for free in ssas for the measure group which may suffice for prototyping but,agreed,where are the other facts?
With this relational database schema, you'll be able to create a basic cube with 5 dimensions and 1 fact table.
The potential problem is that your fact table has no fact, I'd expect something such as salesAmount or another numeric value in your fact. At the moment your fact is a factless fact. Factless fact are a great way to model use relations between dimensions but it's usually not what you try to do in the first hours of cube design.
On our SQL SERVER 2008 R2 database we have an COUNTRIES referential table that contains countries. The PRIMARY KEY is a nvarchar column:
create table COUNTRIES(
COUNTRY_ID nvarchar(50) PRIMARY KEY,
... other columns
)
The primary key contains values like 'FR', 'GER', 'US', 'UK', etc. This table contains max. 20 rows.
We also have a SALES table containing sales data:
create table SALES(
ID int PRIMARY KEY
COUNTRY_ID nvarchar(50),
PRODUCT_ID int,
DATE datetime,
UNITS decimal(18,2)
... other columns
)
This sales table contains a column named COUNTRY_ID, also of type nvarchar (not a primary key). This table is much larger, containing around 20 million rows.
Inside our app, when querying on the SALES table, we filter almost every time on the COUNTRY_ID. Even like this it takes too long to perform most of aggregation queries (even with the proper indexes in place)
We're in a development phase to improve the query performance on the SALES table. My question is:
Does it worth switching the COUNTRY_ID type from nvarchar(50) to the type int? If the column COUNTRY_ID is converted in both tables to the type int, can I expect a better performance when joining the two tables?
I would personally recommend changing COUNTRY_ID from nvarchar(50) to an INT. An int uses 4bytes of data and is usually quicker to JOIN than VARCHAR.
You can also check to see if the space used is reduced by using the stored procedure sp_spaceused
EXEC sp_spaceused 'TableName'
I'm implementing a product database using the single table inheritance (potentially later class table inheritance) model for product attributes. That's all working fine and well but I'm trying to figure out how best to deal with product variants whilst maintaining referential integrity.
Right now a simplified version of my main product table looks like this:
CREATE TABLE product (
id SERIAL NOT NULL,
name VARCHAR(100) NOT NULL,
brand VARCHAR(40) NOT NULL,
color VARCHAR(40)[] NOT NULL
)
(color is an array so that all of the standard colors of any given product can be listed)
For handling variants I've considered tracking the properties on which products vary in a table called product_variant_theme:
CREATE TABLE product_variant_theme (
id SERIAL NOT NULL,
product_id INT NOT NULL,
attribute_name VARCHAR(40) NOT NULL
)
Wherein I insert rows with the product_id in question and add the column name for the attribute into the attribute_name field e.g. 'color'.
Now feel free to tell me if this is an entirely stupid way to go about this in the first place, but I am concerned by the lack of a constraint between attribute_name and the actual column name itself. Obviously if alter the product table and remove that column I might still be left with rows in my second table that refer to it. The functional equivalent of what I'm looking for would be something like a foreign key on attribute_name to the information_schema view that describes the tables, but I don't think there's any way to do that directly, and I'm wondering if there is any reasonable way to get that kind of functionality here.
Thanks.
Are you looking for something like this?
product
=======
id
name
attribute
=========
id
name
product_attribute_map
=====================
product_id
attribute_id
value