Database - Array as Foreign Key - sql

Can we have an Array field as a Foreign Key? For example, I have following two Tables :
Create Sequence Product_id_seq start with 1 increment by 1;
Create Table Purchase (
Productid integer default next value for product_id_seq,
Qty integer,
cost decimal(17,2)
);
Create Sequence InvoiceNo_seq start with 1 increment by 1;
Create Table Sales (
Invoice_Number integer default next value for InvoiceNo_Seq,
qty integer,
product_ids ARRAY,
sale_value decimal(17,2)
);
I would like to add a constraint in table Sales such as "Foreign Key (Product_ids) references Purchase (Productid)".
Why?
eg. I purchased 20 Calculators on 1st July and Another 10 on 10th July. I sold 25 Calculators on 13th July, I should be able to point to the Productids of both the lots of Calculators, combining which they become 25 Nos (20 from productid 1 and 5 from productid 2). this is where array comes into picture.
I Just want to make sure that the Array Contains Values which are present in Purchase.ProductId.
Can this be Achieved?

You can achieve this using Trigger

Related

Check if unique combinations exist in another table

I need to add a constraint when creating a table, Order, such that the unique combination of fields exist within another table.
Table: Product
productId PRIMARY KEY
productNumber
and,
Table: Order
clientId FOREIGN KEY
productId FOREIGN KEY
productNumber
dateBorrowed
dateReturned
I have two tables Product and Order. The productId and productNumber create a unique combination to specify a product as multiple versions of the same product may exist.
When entering values into the Order table the unique combination of productId and productNumber must exist within the Product table, duplicates are allowed as items can be returned and borrowed again at a later date.
I'm not sure how I would go about coding the constraint when creating the Order table, hope that all made sense.
Example Data:
Product
ProductId
ProductNumber
123
1
123
2
675
1
Table
clientId
productId
productNumber
dateBorrowed
dateReturned
10
123
1
1979
1989
10
123
1
1990
2000
12
675
1
2022
2022
07
123
2
1982
2022
The unique combination of fields you describe is in fact the primary key :
CREATE TABLE Product(
productId INTEGER,
productNumber INTEGER,
...
PRIMARY KEY (productId, productNumber)
);
You can reference it in the Order table :
CREATE TABLE "Order"(
...
productId INTEGER,
productNumber INTEGER,
...
FOREIGN KEY(productId, productNumber) REFERENCES Product(productId, productNumber)
);
Please note the Order table name must be quoted, ORDER is a SQLite keyword.
Also foreign keys must be enabled :
PRAGMA foreign_keys = ON;

Violation of primarary key

I am trying to create a many-to-many relationship between two tables Asset and Inventory, I created an intermediate table called Asset_Inventory
One or more assets can be in an inventory, and an inventory can be in one or more assets,but it does not allow me to insert data
Mistake
The data in row 2 was not committed. Error source Message: Violation of PRIMARY KEY CONSTRAINT
PK_INVENTORY_ASSET. Cannot insert duplicate key in object dbo.Inventory_Asset. The duplicate key value (1,1).
-- TABLE INVENTORY
GO
CREATE TABLE Inventory
(
[inventory_id] INT NOT NULL IDENTITY(1,1),
[company_id] INT,
[name] VARCHAR(50),
[observations] VARCHAR(500),
[date_created] DATETIME DEFAULT(GETDATE()),
CONSTRAINT PK_INVENTORY PRIMARY KEY (inventory_id),
CONSTRAINT FK_INVENTORY_COMPANY FOREIGN KEY(company_id) REFERENCES Company(company_id)
)
-- TABLE ASSET
GO
CREATE TABLE Asset
(
[asset_id] INT NOT NULL IDENTITY(1,1),
[company_id] INT,
[code] INT,
[model_name] VARCHAR(50),
[model_number] VARCHAR(50),
[serial_number] VARCHAR(30),
[price] DECIMAL(10,2),
CONSTRAINT PK_ASSET_ID PRIMARY KEY(asset_id),
CONSTRAINT FK_ASSET_COMPANY FOREIGN KEY(company_id) REFERENCES Company(company_id),
CONSTRAINT UQ_ASSET_CODE UNIQUE(code)
)
--TABLE INVENTORY_ASSET
CREATE TABLE Inventory_Asset
(
asset_id INT,
inventory_id INT,
CONSTRAINT PK_INVENTORY_ASSET PRIMARY KEY (asset_id,inventory_id),
CONSTRAINT FK_ASSET_ID FOREIGN KEY (asset_id) REFERENCES Asset(asset_id),
CONSTRAINT FK_IVENTORY_ID FOREIGN KEY (inventory_id) REFERENCES Inventory(inventory_id)
)
UPDATED
it's hard for me to ask this question
N companies have many assets; you need to have control over them. Have a list of assets by company, to which employee it was assigned, or in which department of the company that asset is located. a total of assets by company etc..
What is the purpose of this?
I need to physically label (bar code) each asset with a unique code
Cell phones, monitors, keyboards, servers, PCs, laptops, chairs, furniture, etc...
Once all the assets have been tagged in the
company 1
company 2
company 3
I have to scan each code printed on the asset and make a monthly cut
I have to create a report with this information
In the company 1 an inventory was made in the month of January
Cut of the month of January:
20 monitors (10 dell , 10hp)
20 chairs
10 computers
the next month this cut is made again to see if there is the same quantity, if the 2 inventories of the month of January and February are not the same, some asset was stolen and to be able to identify this
an inventory can have one or more assets, and an asset can be in one or more inventories.
I think I can do this with the Inventory_Asset table
asset_id
iventory_id
1
1
1
1
2
1
3
1
1
1
1
2
2
2
1
2
6
2
1
3
4
3
3
3
1
3
Am I wrong with my solution?
--TABLE INVENTORY_ASSET
CREATE TABLE Inventory_Asset
(
[inventory_id] INT,
[asset_id] INT,
CONSTRAINT FK_ASSET_ID FOREIGN KEY (asset_id) REFERENCES Asset(asset_id),
CONSTRAINT FK_IVENTORY_ID FOREIGN KEY (inventory_id) REFERENCES Inventory(inventory_id)
)
CONSTRAINT PK_INVENTORY_ASSET PRIMARY KEY (asset_id,inventory_id),
PRIMARY KEYS must be unique. That is why you can't add this -- since it conflicts with your primary key. If you don't want that to be unique but you do expect to use it as an index you can make an index that does not enforce uniqueness and make something else your primary key.
The answers and comments here are all correct; but perhaps we need to review what a many-to-many relation can be used for.
Option 1: we just need a link between two entities
This is what you have done. Basically it will serve if you want to know in which Inventories a given Asset is, which Assets a given Inventory holds, etc. In this scenario when you have established the link once (Asset 1 is in Inventory 1) there's no reason to re-establish it with further records.
Option 2: we want to store some information about the relation
This is what I suspect you really wanted. Suppose for instance you want to store how many Assets of type 1 are in Inventory 1. In this case what you want is to add a "Quantity" column to your Inventory_asset table. Once more, if there are 3 Assets of type 1 in Inventory 1 you won't duplicate the records: you will just create one record and put 3 in the new column.
Option 3: we really need multiple records
Suppose you want to store not only how many Assets of a given type are in a given Inventory, but also on which date a few of them were put there. So you may have 2 type 1 Assets put in Inventory 1 on May, 1st, and other 3 of them on May, 15th. In this case the date must become part of the PK, so that the system (and you too!) can distinguish between the different records. You may also decide to create an auto-increment column and use it as a PK instead; but note that while it may be simpler to handle, it would allow for unvoluntarily creating duplicate records, so I wouldn't recommend it.

Creating tables - integrity constraints

Create the following tables:
Customer
KNr (primary key)
Name (at most 15 characters)
City (at most 10 characters)
Country (at most 10 characters)
Balance (Type FLOAT)
Discount (Type FLOAT)
Products
PNr (greater than 1 and primary key)
Descr (not NULL, at most 10 characters and unique)
Weight (Type FLOAT)
Think about the integrity constraints for the columns Price, StorageLocation and Stock.
Orders
OrdNr (Type INTEGER, greater than 0 and primary key)
Mon (Type INTEGER, not NULL and between 1 and 12)
Day (Type INTEGER, not NULL and between 1 and 31)
PNr (Foreign Key)
KNr (Foreign Key)
The attributes Month, Day, Pnr and Knr must together be unique. Think about the integrity constraints for the columns Quantity, Sum and Status.
I have done the following :
For 1 :
CREATE TABLE Customer
(
KNr PRIMARY KEY,
Name CHAR(15),
City CHAR(10)
Country CHAR(10)
Balance FLOAT
Discount FLOAT
);
Is that correct?
For 2 :
CREATE TABLE Products
(
PNr PRIMARY KEY CHECK (PNr > 1) ,
Descr NOT NULL CHAR(10) UNIQUE.
Weight FLOAT
Price FLOAT CHECK (Price > 0) // Is checking if it is positive an integrity constraint?
StorageLocation CHAR(15) // What integrity constraint do we use here? If it is not Null for example?
Stock INTEGER // What integrity constraint do we use here? If it is not negative for example?
);
Is that correct?
For 3 :
CREATE TABLE Orders
(
BestNr INTEGER PRIMARY KEY CHECK (BestNr > 0) ,
Mon INTEGER NOT NULL CHECK(Mon >= 1 and Mon <=12)
Day INTEGER NOT NULL CHECK(Day >= 1 and Day <=31)
FOREIGN KEY (PNr) REFERENCES Customer (PNr),
FOREIGN KEY (KNr) REFERENCES Products (KNr)
Quantity INTEGER CHECK(Quantity >0) // It is the ordered quantity, or not? What integrity constraints can we consider?
Sum FLOAT // Is this the sum of invoices? Or what is this meant? What integrity constraints can we consider?
Status CHAR(20) // It is meant if is paid, delivered, etc? So this contains words, right? What integrity constraints can we consider?
UNIQUE (Mon, Day, Pnr, Knr)
);
Do we write that as in the last line that the attributes Month, Day, Pnr and Knr must together be unique ?
You are actually pretty close if viewed as logical model defining requirements. From a physical model however, the syntax is considerable off.
I will not do each table but just Orders, and I will slice and dice along the way, leaving some things you need to correct and some suggestions for your considerations.
First off If you want comment on your ddl you can do so, but they begin with -- instead of //. A better approach just use Comment On where they become part of the permanent record.
BestNr:
As a column name nothing wrong but is it clear what BestNr refers to, and what makes it better than any other number. Perhaps a better name would be Ord_nr. (But the is of course just an opinion). Declaring it as Primary comes with 2 automatic constraints: Not Null and Unique. Check constraint again there is nothing wrong. However a better process would be just tell the DBMS to generate identity column (see Create table ... generated ...).
Mon and Day:
Technically nothing wrong. However there is a data integrity hole as it still permits invalid date. The date Feb 30 would pass both your constraints. But it is still an invalid date. Other months have the same issue, day = 31 for a month with only 30 days passes the constraints but remains invalid. To ensure only valid dates just define a date column. This also eliminates the need for the check constraint. The month and date can be extracted when needed.
FOREIGN KEY (PNr) REFERENCES Customer (PNr): FOREIGN KEY (KNr) REFERENCES Products (KNr):
Your reference is backwards. PNr refers to Product, KNr to customer. However you must define them as columns then generate the FK. While nothing is wrong with these as columns names, are the descriptive of what they refer to. PNr perhaps, but not so KNr (unless Customer is always referred to as K...) Perhaps better prod_nr and cust_nr. (but perhaps no product reference at all - later).
Sum:
This column can easily be derived when needed, and will be difficult to keep current (what happens when another item is added to the Order, or Updated, or Deleted). Further this is a very poor choice for a column name as it is a SQL Standard reserved word (not by all RDBMS however, Postgres being one). Drop the column and derive it when needed.
Status:
You would want to constrain this to a set of predefined values. Either a CHECK constraint, an ENUM or a lookup (reference) table.
Normalization:
Consider normalizing a bit further. An order typically will contain multiple items (lines). These can/should be extracted into another table; call it Order_Lines and move PNr and Quantity into it.
Taking all the above into consideration arrive at:
-- method to constrain status
create type order_status as enum ('pending', 'picked', 'shipped', 'delivered', 'billed', 'paid', 'back ordered', 'on hold', 'canceled' ); -- or others
create table orders ( ord_nr integer generated always as identity primary key
, ord_dt date
, cust_nr integer references customers (cust_nr)
, status order_status -- questionable: Can it be derived?
, constraint one_per_cust_per_day unique (cust_nr, ord_dt) -- combine multiple orders for customer into 1 per day. ??
);
create table order_lines ( ord_ln_nr integer generated always as identity primary key -- optional
, ord_nr integer not null references orders(ord_nr)
, prod_nr integer not null references products(prod_nr)
, quantity integer not null check (quantity>0)
, price float -- Note1
, status order_status
, constraint one_ln_per_ord_prod unique ( ord_nr, prod_nr)
);
Note1: Normally do not copy columns from referenced tables. You normally avoid this as it creates duplicate data, just get the value through the reference. However, price tends to be a volatile column. If a price change occurs, we should not automatically apply that to existing orders. For this reason the Price from the Product will be copied when order is placed.

How to insert data in purchase tabele with diffrent price without data dedundancy

i have create a table name as purchase
CREATE TABLE purchase(
item_id NUMBER(20) PRIMARY KEY,
purchase_qty VARCHAR2(50),
sup_name VARCHAR2(50),
purchase_price NUMBER (10)
);
and insert data
INSERT INTO purchase
VALUES(0001,170,'MG Trading',100);
I want to be insert same item name with different price such as 120 How it possible because item_id =primary key and if insert to anther row with out PK it's effect data data redundancy problem , then i have remove primary key and insert another value
INSERT INTO purchase
VALUES(0001,30,'abc_company',120);
now total item qty 170+30=200 a customer need qty 180 how can i sale it ?? because my item is oil type product and can not print barcode for oil
this entity crate a oil pump application
You can not have two register with the same value to the Primary Key, doesn't matter the other columns values.
I think, as #GordonLinoff suggested, your model is the problem.
You should make something like this.

Advanced (?) SQL Joins?

I am a bit lost as to how to explain this, so I will try to give an example of some tables (+ data) and then the result that I am after (all my table columns are NOT NULL):
Table: Customers
Id int primary key
Name varchar(250)
Table: Stats (Date, CustomerId is the primary key)
Date (date)
CustomerId (int) - foreign key to Customers table
Earning (money)
Table: Bonus
Id int primary key
CustomerId int - foreign key to Customers table
Date date
Amount money
Table: Payments
Id int primary key
DateFrom date,
DateTo date,
CustomerId bigint - foreign key to Customers table
Table: CampaignPayment
Id int primary key
PaymentId int - foreign key to payments table
Quantity int
UnitPrice money
Table: BonusPayment
Id int primary key
PaymentId int - foreign key to payments table
Amount money
The idea here is that everytime a customer does something that is supposed to earn them money, it goes into the stats table. Customers can also receive different kinds of bonuses which goes into the bonus table. Every so often I need to create an invoice for the customers (Payments table) which will list the stuff from the stats table + the bonus table within the specified time period and that will generate the invoice (that is the payments table defines who the invoice is for, which period and the campaignpayment and bonuspayment table defines what is being paid and why).
Now - I need to be able to join all these tables up to be able to get an output of the following:
CustomerId | CustomerName | PaymentId | Amount | BonusAmount | DateFrom | DateTo
Amount is the summed Amount ( SUM(Quantity * UnitPrice) ) from the CampaignPayment table, and BonusAmount is the summed Amount ( SUM(Amount) ) from the BonusPayment table. DateFrom and DateTo is from the Payments table.
The trick is that for every customer within a given month where every single day of that month is not covered, I want a row with the following data:
CustomerId | CustomerName | NULL | (Stats.Earning - Amount Earned from possible payments within the month) | (Bonus.Amount - Amount Earned possible bonuses that is in payments within the month) | First day of month | Last day of month
I may need a bit more of complex logic as to how to calculate the amount and bonus amount within these "empty" rows but as for now, that is what I need to begin with.
How would I go about this? I know how to get the "initial" bit done, but how would I go about adding in these "empty" rows? I hope I explained the problem well enough in detail and that you can see the idea here - if not let me know and I will try to explain further.
The database is MS SQL Server 2008.
EDIT: Also alternatively an "empty" row for every customer per month is also and acceptable solution.
I'd make an auxiliary table with "every single day of that month" to ease identifying if "every single day of the month is not covered" (a somewhat ambiguous spec, but the aux table should help whether you mean "no day is covered" or "some days are not covered" and whether a day is considered "covered" if it has either a bonus or stats, or if it needs to have both to be considered "covered" -- these ambiguities are why I'm not going to even try and sketch the SQL using this aux table;-). Then I'd UNION the "empty rows" to the "initial bit" that you already know how to get done -- seems a perfect task for UNION!-)