Making sure Identity column doesn't allow change in another value - sql

I have an identity column known as RowId which is needed. However, I have an issue where I am seeing multiple instances of that same RowID 5-10 times where the customerNumber changes and that should not be allowed. For instance:
RowID: CustomerNumber:
2556892 25231564656522
2556892 25232264686453
How can I make sure my table does not allow the CustomerNumber to change? The point of having an identity column is to have different RowId's when a value is added such as a new CustomerNumber. Somehow instead of the new CustomerNumber getting a new rowId it is being modified and they are changing the CustomerNumber. How can this be prevented?

It sounds like you need a new table for customers:
create table Customers as (
CustomerId int identity(1, 1) primary key,
CustomerNumber varchar(20) unique -- or whatever
-- add more columns about customers
);
Voila! You have only one CustomerId per CustomerNumber. This is appropriate for foreign key relationships. You can then remove CustomerNumber from your current table, rename rowid to CustomerId (which is more descriptive), and define an appropriate foreign key relationship.

Related

Can I use identity for primary key in more than one table in the same ER model

As it is said in the title, my question is can I use int identity(1,1) for primary key in more than one table in the same ER model? I found on Internet that Primary Key need to have unique value and row, for example if I set int identity (1,1) for table:
CREATE TABLE dbo.Persons
(
Personid int IDENTITY(1,1) PRIMARY KEY,
LastName varchar(255) NOT NULL,
FirstName varchar(255),
Age int
);
GO
and the other table
CREATE TABLE dbo.Job
(
jobID int IDENTITY(1,1) NOT NULL PRIMARY KEY,
nameJob NVARCHAR(25) NOT NULL,
Personid int FOREIGN KEY REFERENCES dbo.Persons(Personid)
);
Wouldn't Personid and jobID have the same value and because of that cause an error?
Constraints in general are defined and have a scope of one table (object) in the database. The only exception is the FOREIGN KEY which usually has a REFERENCE to another table.
The PRIMARY KEY (or any UNIQUE key) sets a constraint only on the table it is defined on and is not affecting or is not affected by other constraints on other tables.
The PRIMARY KEY defines a column or a set of columns which can be used to uniquely identify one record in one table (and none of the columns can hold NULL, UNIQUE on the other hand allows NULLs and how it is treated might differ in different database engines).
So yes, you might have the same value for PersonID and JobID, but their meaning is different. (And to select the one unique record, you will need to tell SQL Server in which table and in which column of that table you are looking for it, this is the table list and the WHERE or JOIN conditions in the query).
The query SELECT * FROM dbo.Job WHERE JobID = 1; and SELECT * FROM dbo.Person WHERE PersonID = 1; have a different meaning even when the value you are searching for is the same.
You will define the IDENTITY on the table (the table can have only one IDENTITY column). You don't need to have an IDENTITY definition on a column to have the value 1 in it, the IDENTITY just gives you an easy way to generate unique values per table.
You can share sequences across tables by using a SEQUENCE, but that will not prevent you to manually insert the same values into multiple tables.
In short, the value stored in the column is just a value, the table name, the column name and the business rules and roles will give it a meaning.
To the notion "every table needs to have a PRIMARY KEY and IDENTITY, I would like to add, that in most cases there are multiple (independent) keys in the table. Usually every entity has something what you can call business key, which is in loose terms the key what the business (humans) use to identify something. This key has very similar, but usually the same characteristics as a PRIMARY KEY with IDENTITY.
This can be a product's barcode, or the employee's ID card number, or something what is generated in another system (say HR) or a code which is assigned to a customer or partner.
These business keys are useful for humans, but not always useful for computers, but they could serve as PRIMARY KEY.
In databases we (the developers, architects) like simplicity and a business key can be very complex (in computer terms), can consist of multiple columns, and can also cause performance issues (comparing a strings is not the same as comparing numbers, comparing multiple columns is less efficient than comparing one column), but the worst, it might change over time. To resolve this, we tend to create our own technical key which then can be used by computers more easily and we have more control over it, so we use things like IDENTITYs and GUIDs and whatnot.

Two postgresql tables referencing each other

Question may be basic, I don't have any experience with databases.
I have a postgres db with some tables. Two of them are dates and accounts.
The date table has an account_id field referencing an id table in an account table and a balance field that represents the balance that account had at that date. So, many date entities may reference one account entity, many-to-one, okay.
But an account table also has an actual_date field, that must reference the date entity, with actual balance this account has. One account entity may reference one actual date entuty, but date entity can have one or zero account entities referncing it. And if it does have an account referencing it with it's actual_date, it will always be the same account, date itself referencing with account_id.
What kind of relathinship is this? Is it even possible to implement? And if it is, how do I do it?
I came up with this piece of code, but I have no clue if it does what I think it does.
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users,
actual_date_id DATE UNIQUE REFERENCES dates
);
CREATE TABLE dates (
id SERIAL PRIMARY KEY,
account_id INT REFERENCES accounts,
date DATE,
balance INT,
unconfirmed_balance INT
);
P.S. I create tables with init.sql but work with them with sqlalchemy and it would be greate if someone could also show how to define such model with it.
As written the SQL script would never work for two reasons:
a foreign key can only reference the primary key of a table, not any arbitrary column in it. So actual_date_id should be an integer in order to be able to reference the primary key of the dates table.
you can't reference a table that hasn't been created yet, so the foreign key between accounts and dates must be created after both tables are created.
With circular foreign keys it's usually easier to define at least one of them as deferrable, so that you can insert them without the need of e.g. an intermediate NULL value.
So something along the lines (assuming that users already exists)
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users,
actual_date_id integer UNIQUE -- note the data type
);
CREATE TABLE dates (
id SERIAL PRIMARY KEY,
account_id INT REFERENCES accounts,
date DATE,
balance INT,
unconfirmed_balance INT
);
-- now we can add the foreign key from accounts to dates
alter table accounts
add foreign key (actual_date_id)
references dates (id)
deferrable initially deferred;
It might be better to avoid the circular reference to begin with. As you want to make sure that only one "current balance" exists for each account, this could be achieved by adding a flag in the dates table and getting rid of the actual_date_id in the accounts table.
CREATE TABLE accounts (
id SERIAL PRIMARY KEY,
user_id INT REFERENCES users
);
CREATE TABLE dates (
id SERIAL PRIMARY KEY,
account_id INT REFERENCES accounts,
is_current_balance boolean not null default false,
date DATE,
balance INT,
unconfirmed_balance INT
);
-- this ensures that there is exactly one row with "is_current_balance = true"
-- for each account
create unique index only_one_current_balance
on dates (account_id)
where is_current_balance;
Before you change a row in dates to be the "current one", you need to reset the existing one to false.
Unrelated, but:
With modern Postgres versions it's recommended to use identity columns instead of serial

Creating unique primary key to ignore duplicates

I have a main large table which I have had to put into 3rd normal form and into smaller tables (with primary and foreign keys linking them). The table is about renting books.
I have a customer table which I need to create a primary key for. In the main large table there are duplicates of the customer_id, as the table as a whole is for renting the books, so one customer may have more than one renting.
The table I am currently trying to add a primary key for will not have any nulls or duplicates, however i am unsure how to create the primary key for this without the error- unsure how to make it unique.
CREATE TABLE customer AS
SELECT cust_id, country_id, name, address, postcode
FROM BOOKS
WHERE cust_id != 0;
ALTER TABLE customer
ADD PRIMARY KEY (cust_id);
Is anyone able to help me in how to create the primary key on my customer table, but just taking each unique cust_id from the main table.
In SQL Server the straightforward way to add unique keys is to use IDENTITY. Identity fields are integer fields that auto populate successive values by a specified start value and interval. If you don't specify the interval it will start at 1 and increase the value by 1 each time a value is assigned.
While it's usually done when creating a table, you can do it in your ALTER TABLE step, and it will assign values when added to an existing table. I've explicitly specified the start value and interval that matches the default to show the syntax :
ALTER TABLE customer
ADD cust_id int not null PRIMARY KEY IDENTITY(1,1)

Normalizing a table with duplicate rows and many-to-many relationships

I am designing the database for an accounting system, currently working on the Expenses table.
According to IRS rules, whenever you update a row in any accounting table, you need to cancel out the existing row by negating its values, and create a new row with the modified information, like so:
Set the row's Status flag to "Modified"
Create an identical copy of this row, with all Money fields negated, so that the sum of the two rows is 0
Create a 3rd row, identical to the first one, with the modified data
Each expense has an identity field called ID for internal identification purposes, and an ExpenseID field, which identifies the transaction to the users. The two cannot be the same, because
ExpenseID can be repeated twice if the transaction was modified and its row was duplicated.
ExpenseIDs MUST be consecutive and NEVER have gaps, while identity fields can skip numbers if a transaction is rolled back and the identity is not reseeded.
In general, I believe the primary key should have no business meaning whatsoever.
My problem is that there are other tables used to link these expenses Many-To-Many to other objects in our system. E.g.: each expense can be linked to documents, folders, users, etc.
So it looks something like this:
create table Expenses (
ID int not null identity(1,1),
ExpenseID int not null,
Amount Money not null,
Status tinyint not null,
[...]
)
create table Expenses_Users (
ExpenseID int not null,
UserID int not null
)
alter table Expenses_Users add constraint FK_Expenses_Users_Expenses
foreign key (ExpenseID) references Expenses (ID)
alter table Expenses_Users add constraint FK_Expenses_Users_Users
foreign key (UserID) references Users (ID)
Now, because of the IRS guidelines, I have to duplicate not only rows in the Expenses table, but also in Expenses_Users, and any other table that links Expenses to other tables.
I have two ideas on how to solve this:
Option One: Normalize Expenses like this:
create table Expenses (
ID int not null identity(1,1),
ExpenseID int not null,
Status tinyint not null,
[...]
)
create table ExpensesNormalized (
ExpenseID int not null,
Amount Money not null
)
alter table ExpensesNormalized add constraint FK_ExpensesNormalized_Expenses
foreign key (ExpenseID) references Expenses(ExpenseID)
This means I'll only have to link external tables to Expenses, not ExpensesNormalized. Also, when updating an expense, I'll only duplicate and negate the data in ExpensesNormalized, which means I'll have far less redundant data in the Expenses table.
However, I'll have to use a JOIN clause every single time I SELECT from Expenses. I fear a performance hit because of this.
Option Two: Use the same tables I use now, but have the field Expenses_Users.ExpenseID point to the field Expenses.ExpenseID. This means that I won't have to duplicate any external objects because they'll point to ExpenseID, which may occur several times.
However, this will not be a real foreign key because SQL Server does not allow foreign keys to non-unique fields, so I'll have to implement foreign key logic in a trigger.
I'm having a hard time deciding between these two options. Any feedback would be appreciated.

How to Auto-Increment Non-Primary Key? - SQL Server

CREATE TABLE SupplierQuote
(
supplierQuoteID int identity (3504,2) CONSTRAINT supquoteid_pk PRIMARY KEY,
PONumber int identity (9553,20) NOT NULL
.
.
.
CONSTRAINT ponumber_uq UNIQUE(PONumber)
);
The above ddl produces an error:
Msg 2744, Level 16, State 2, Line 1
Multiple identity columns specified
for table 'SupplierQuote'. Only one
identity column per table is allowed.
How can i solve it? I want PONumber to be auto-incremented.
If SupplierQuoteId and PONumber are generated when a row is inserted, then the two "identity" columns would be assigned in lockstep (3504 goes with 9553, 3506 goes with 9573, 3508 goes with 9593, etc.). If this assumption is true, then you presumably could make PONumber a calculated column, like so:
CREATE TABLE SupplierQuote
(
supplierQuoteID int NOT NULL identity (3504,2) CONSTRAINT supquoteid_pk PRIMARY KEY,
PONumber AS (10 * supplierQuoteID - 25487)
.
.
.
);
I made supplierQuoteId NOT NULL, which ensures that PONumber will also be NOT NULL. Similarly, you no longer need the unique constraint on PONumber, as it will always be unique. (It is possible to build indexes on calculated columns, if you need one for performance.)
You can't have more than one identity column per table. I think your best bet would be to pull the PO data into a separate table, then relate the two with a FK column.
SupplierQuote
-------------
supplierQuoteID (PK/identity)
purchaseOrderID (FK to PurchaseOrder.purchaseOrderID)
otherColumn1
PurchaseOrder
-------------
purchaseOrderID (PK/identity)
otherColumn1
You can't solve you - you can only have a single IDENTITY column per table. No way around that, sorry.
The only "hackish" solution would be to have a separate table for nothing more than having an INT IDENTITY field, and grabbing the newest value from that helper table into your entity upon insertion (e.g. with a trigger). Not very pretty, but it might work for you.
If there is only one PO id per supplier quote, then why not simply use the supplier quote id as the PO id?
If there can be more than one, you must have a sepapate table with a foreign key constraint. You can of course use cascade delete to delete from this table but this can be dangerous if you delete too many records (causing lockups) or personally I wouldn't want to delete a supplier quote if a PO number has been created as that means the item quoted was actually bought. You do not want to ever destroy records of things that were actually purchased. Since you will likely have multiple POS (I got a quote on six things and first bought three of them, then bought two others the next week) per quote and since it is likely you will want to store specific information about the purchase order, I recommend a separate table. To do anything else is going to cause you problems in the long run.
I think I'd use a trigger to fill the "second identity".
Circumvent auto increment in non identity column.(MS SQL) I don't think this is the best practice though! JUst a quick fix solution.
INSERT INTO [dbo].[Employee]
([EmpID]
,[Name]
,[Salary]
,[Address]
,[datecoded])
VALUES
( (select top 1 EmpID from dbo.Employee order by EmpID desc) + 1
, 'name_value'
, 123456
,'address_value'
, GETDATE())