in sql i have a table of items. An item can have multiples prices. But when i come to using the data, most of the time i only need the currentPrice that i can find with the date.
My question : Would it be wrong to have 2 relation on price where and Item would have a relation with the currentPrice and all the price. Do there is a solution for this kind of problem to prevent complication in my mvc. Im currently using a viewModel with and the current price but if i could handle this in the database it seem better to me. (tell me if its not).
Note: I don't think this exact methode would work since I would need to create my price table before my item table and the same for the item table. But this show my problem.
Thanks alot for your help.
CREATE TABLE Item.Items
(
ItemId INT NOT NULL
CONSTRAINT PK_Items_ItemId
PRIMARY KEY
IDENTITY,
--------------------------------------------------
--CurrentPriceId INT NOT NULL
CONSTRAINT FK_Prices_Items
FOREIGN KEY REFERENCES Item.Items (ItemId),
--------------------------------------------------
Name VARCHAR(100) NOT NULL,
Points INT NOT NULL DEFAULT 0,
Description VARCHAR(5000) NULL
)
CREATE TABLE Item.Prices
(
PriceId INT NOT NULL
CONSTRAINT PK_ItemPrices_ItemPriceId
PRIMARY KEY
IDENTITY,
ItemId INT NOT NULL
CONSTRAINT FK_ItemPrices_Item
FOREIGN KEY REFERENCES Item.Items (ItemId),
EffectiveDate DATETIME NOT NULL,
Value MONEY NOT NULL
)
better would be:
CREATE TABLE Item.Items
(
ItemId INT NOT NULL
CONSTRAINT PK_Items_ItemId
PRIMARY KEY IDENTITY,
--------------------------------------------------
CurrentPrice MONEY NOT NULL, -- optional optimization, redundant as
-- current price is available from item.Prices
--------------------------------------------------
Name VARCHAR(100) NOT NULL,
Points INT NOT NULL DEFAULT 0,
Description VARCHAR(5000) NULL
)
CREATE TABLE Item.Prices
(
ItemId INT NOT NULL
CONSTRAINT FK_ItemPrices_Item
FOREIGN KEY REFERENCES Item.Items (ItemId),
EffectiveUtc DATETIME NOT NULL,
Price MONEY NOT NULL,
Constraint [ItemPricesPK] PRIMARY KEY CLUSTERED
(
[ItemId] ASC,
[EffectiveUtc] ASC
)
)
As mentioned by #popovitz, you can always get the price as of any specific date using a correlated subquery ...
Select i.name, p.price
From Item.Items i
Join Item.Prices p
ON i.ItemId = p.ItemId
Where p.EffectiveUtc =
(Select Max(EffectiveUtc )
From Item.Prices
Where ItemId = i.ItemId
And EffectiveUtc <= #asOfDate)
I would not recommend adding a currentPrice column, because you would have to constantly make sure that the item table is being updated whenever there a new price becomes effective. It's not that hard to query the current price when you have a table that contains the prices with an EffectiveDate column:
SELECT i.name, p.price FROM Items i
INNER JOIN Prices p ON i.ItemId = p.ItemId
WHERE p.EffectiveDate =
(SELECT MAX(EffectiveDate) FROM Price
WHERE EffectiveDate <= SYSDATE
AND ItemId = i.ItemId)
This will select the correct price for the current system time, assuming that (EffectiveDate, ItemId) is unique for the table prices.
Related
i have atable such as codes table have these values:
Major_code
minor_code
name
1
0
Country
1
1
USA
1
2
JOR
2
0
Food
2
1
Burger
2
2
Mansaf
I need to create table have these columns (ID, Country_ID , Food_ID) what is the best constraint that resolve this issue?
Having a single lookup table for all reference codes is a very poor design, to the point of almost being a SQL anti-pattern. It is likely to have performance issues. It is also difficult to ensure that the value of COUNTRY_MINOR_CODE references an actual country minor code in the reference table. Which brings us to this statement:
I need to create table have these columns (ID, Country_ID , Food_ID)
Can't be done. Or at least it can be done but you can't build foreign keys on that, because minor keys are not unique in the referenced table. But if you are set on a single table, say lookup_table with primary key defined on (major_code, minor code), you need this:
create table country_food (
id number primary_key
,country_major_code number not null
,country_minor_code number not null
,food_major_code number not null
,food_minor_code number not null
,constraint country_major_code_ck check (country_major_code = 1)
,constraint country_minor_code_ck check (country_minor_code != 0)
,constraint food_major_code_ck check (country_major_code = 2)
,constraint food_minor_code_ck check (country_minor_code != 0)
,constraint country_code_fk foreign key (country_major_code, country_minor_code) references lookup_table
,constraint food_code_fk foreign key (food_major_code, food_minor_code) references lookup_table
)
/
The hard coding of values, the additional check constraints, the increased complexity of joining to look up the name ... These are all reasons why you should choose to have separate tables for FOOD, COUNTRY, etc.
create table country (
country_id number primary_key
,country_name varchar2(24) not null
)
/
create table food (
food_id number primary_key
,food_name varchar2(24) not null
)
/
create table country_food (
id number primary_key
,country_id number not null
,food_id number not null
,food_major_code number not null
,constraint country_code_fk foreign key (country_id) references country
,constraint food_code_fk foreign key (food_id) references food
)
/
If I've got it right, you can get all Country+Food pairs with the query
select t1.minor_code counrty_id, t2.minor_code food_id
from (
select minor_code
from codesTable
where Major_code = (
select c.Major_code
from codesTable c
where c.minor_code=0 and c.name='Country')
) t1
cross join (
select minor_code
from codesTable
where Major_code = (
select c.Major_code
from codesTable c
where c.minor_code=0 and c.name='Food')
) t2
You can use the query to insert data into a table with an autogenerated ID or use it any other way.
First you need to consider the design of the tables
Table of country
Table of foods
Tables of food_country -------- relationship => many-to-many
CREATE TABLE Country
(
Major_code numeric(15) not null,
minor_code numeric(15),
name varchar(50),
CONSTRAINT country_pk PRIMARY KEY (Major_code)
);
CREATE TABLE Food
(
Food_ID numeric(15) not null,
//...........................
name varchar(50),
CONSTRAINT food_pk PRIMARY KEY (Food_ID)
);
CREATE TABLE Counry_Food
(
ID numeric(10) not null,
Country_ID numeric(15) not null,
Food_ID numeric(15) not null,
CONSTRAINT fk_country
FOREIGN KEY (Country_ID)
REFERENCES Country(Major_code),
CONSTRAINT fk_food
FOREIGN KEY (Food_ID)
REFERENCES supplier(Food_ID),
);
assuming these 3 tables
create table item(
item_id integer NOT NULL primary key,
name varchar(50) NOT NULL,
description varchar(150) NOT NULL,
in_stock integer NOT NULL
)
create table customer(
customer_id VARCHAR(9) NOT NULL primary key,
name VARCHAR(50) NOT NULL,
lastname VARCHAR(50) NOT NULL,
phone VARCHAR(15) NOT NULL,
join_date DATE NOT NULL
)
create table purchase(
purchase_id integer references item,
customer_id varchar(9) references customer,
purchase_date TIMESTAMP NOT NULL,
amount INTEGER NOT NULL,
PRIMARY KEY(purchase_id, customer_id, purchase_date)
)
how could I get each unique name and the total amount of items purchased?
how could I get each purchase name and the buyer's name and lastname?
how could I get each item and how many of it were sold?
The two topics you are looking to learn are how to use GROUP BY and how to JOIN tables. Here's an example (more or less) that answers your first question and uses both tools:
select
C.customer_id as customer_id,
max(C.name) as customer_name,
sum(amount) as total_amount
from customer C
left join purchase P on C.customer_id = P.customer_id
group by C.customer_id
i get this error when i execute
SQL71516 :: The referenced table '[dbo].[Stock]' contains no primary or candidate keys that match the referencing column list in the foreign key. If the referenced column is a computed column, it should be persisted.
CREATE TABLE [dbo].[Customer]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[FirstName] NCHAR(10) NOT NULL,
[LastName] NCHAR(10) NOT NULL,
[Email] NCHAR(10) NOT NULL UNIQUE,
[Mobile] NCHAR(10) NOT NULL
)
CREATE TABLE [dbo].[Stock]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[name] NCHAR(10) NOT NULL,
[price] INT NOT NULL,
CustomersID int NOT NULL,
FOREIGN KEY (CustomersID) REFERENCES Customer(Id)
ON DELETE CASCADE ON UPDATE CASCADE
)
CREATE TABLE [dbo].[Order]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[Date] DATE NOT NULL,
[Quantity] INT NOT NULL,
Stock_price int NOT NULL,
[Total Value] AS (Quantity)*(Stock_price) PERSISTED,
CONSTRAINT [FK_Stock_price1] FOREIGN KEY ([Stock_price])
REFERENCES [Stock](price) ON DELETE CASCADE ON UPDATE CASCADE
)
You can only use columns that are uniquely indexed. The price column is not. However, I suspect that the foreign key that's giving you a hard time is actually wrong anyway. I also don't think you should have a CustomerId reference in your Stock table.
in fact, the basic standard database structure for a store is this:
Customer table
id, name [, other details]
Stock table
id, name, price [, other details]
Order table
id, customer id, order date [, other details]
Order details table
id, order id, item id, quantity, price [, other details]
This way, an order is related to a single customer, an can contain multiple items.
The price column in the order details table represents the item price at the date of the order - while the price column in the stock table represents the item's current price.
[Stock].[price] is not a key, that's why you can't define a foreign key on that column.
If 2 products (A and B) in table Stock have the same price, what would be the reference?
You can either set a key on this column, such as UNIQUE but this will prevent you to have differents prices in your table Stock.
I suggest you to use the [Stock].[Id] key as reference for your foreign key, such as :
CREATE TABLE [dbo].[Order]
(
[Id] INT NOT NULL PRIMARY KEY IDENTITY,
[Date] DATE NOT NULL,
[Quantity] INT NOT NULL,
Stock_id int NOT NULL, -- <--- changed column name
[Total Value] AS (Quantity)*(Stock_price) PERSISTED,
CONSTRAINT [FK_Stock_id1] FOREIGN KEY ([Stock_id]) -- <-- changed column name
REFERENCES [Stock](Id) ON DELETE CASCADE ON UPDATE CASCADE
-- ^--^------------------------------------- Notice this
);
My SQL code is not working I get 0 rows affected when my code is supposed to be correct.
use CA
truncate table salesFacts
INSERT INTO CA..salesFacts
(date,customerNumber,productCode,orderNumber,productLine,price,quantity)
SELECT
replace(CONVERT(DATE,o.OrderDate, 112),'-',''),
c.customerNumber,
pr.productCode,
o.orderNumber,
pl.productLine,
od.priceEach,
od.quantityOrdered
FROM
CA..orders o,
CA..products pr,
CA..customers c,
CA..orderDetails od,
CA..productLines pl
WHERE
o.customerNumber = c.customerNumber
AND od.productCode = pr.productCode
AND od.orderNumber = o.orderNumber
AND pr.productLine = pl.productLine
This is the table for it:
CREATE TABLE salesFacts (
date Datetime NOT NULL,
customerNumber int NOT NULL,
productCode varchar(15) NOT NULL,
orderNumber int NOT NULL,
productLine varchar(50) NOT NULL,
price decimal(6,2) NOT NULL,
quantity INT NOT NULL,
primary key(customerNumber, productCode, orderNumber, productLine),
foreign key (customerNumber) references Customers (customerNumber),
foreign key(productCode) references products(productCode),
foreign key (orderNumber) references orders(orderNumber),
foreign key (productLine) references productLines(productLine))
Thank you so much for your help in advance. I have been straggling with this code for hours and still could not do it. Any help would be appreciated
basically, i need to make database for plants and their harvest dates.
For example, table with all the plants.
CREATE TABLE plant
(
plant_name NVARCHAR(20) NOT NULL
PRIMARY KEY ,
best_to_harvest_day INT NOT NULL ,
best_to_harvest_month NVARCHAR(15)
)
Example for plant entry: Rose 16 December
And another table called harvests
Where are multiple harvested plants and dates when they were harvested.
CREATE TABLE harvests
(
plant_name nvarchar(20) NOT NULL FOREIGN KEY REFERENCES plant(plant_name),
amount int NOT NULL,
havested_day int NOT NULL,
harvested_month nvarchar(15),
harvested year int NOT NULL
)
And this method does work, because i can make a sql query to compare which plants are harvested at their best time etc.
But isnt there a tidy way?
something like this: (using the date)
CREATE TABLE plant
(
plant_name NVARCHAR(20) NOT NULL
PRIMARY KEY ,
best_to_harvest DATE --But here should only be day and month, not year.
)
CREATE TABLE harvests
(
plant_name NVARCHAR(20) NOT NULL
FOREIGN KEY REFERENCES plant ( plant_name ) ,
amount INT NOT NULL ,
harvested DATE --But here i need full date year,day,month
)
Bottom line is that i need to compare them.
Okay, i think i can use EXTRACT(unit FROM date)
and then compare them but the question still stands, how to make plant table date not to consist of year?
First, store the date parts as numbers and check their values. This isn't perfect, but probably good enough:
CREATE TABLE plant (
plant_id int not null PRIMARY KEY,
plant_name nvarchar(20) NOT NULL UNIQUE,
best_to_harvest_day int NOT NULL,
best_to_harvest_month int not NULL,
check (best_to_harvest_day between 1 and 31),
check (best_to_harvest_month between 1 and 12)
);
Note the inclusion of an integer identity primary key. This is recommended, because integers are more efficient for foreign key references.
Then use date for the harvest:
CREATE TABLE harvests (
harvest_id int not null primary key,
plant_id int NOT NULL FOREIGN KEY REFERENCES plant(plant_id),
amount int NOT NULL,
harvested date --But here i need full date year,day,month
);
And you can do:
select h.*,
(case when p.best_to_harvest_day = day(h.harvest_day) and
p.best_to_harvest_month = month(h.harvest_month)
then 'Y' else 'N'
end)
from harvest h join
plant p
on h.plant_id = p.plant_id;