versioning of a table - sql

anybody has seen any examples of a table with multiple versions for each record
something like if you would had the table
Person(Id, FirstName, LastName)
and you change a record's LastName than you would have both versions of LastName (first one, and the one after the change)

I've seen this done two ways. The first is in the table itself by adding an EffectiveDate and CancelDate (or somesuch). To get the current for a given record, you'd do something like: SELECT Id, FirstName, LastName FROM Table WHERE CancelDate IS NULL
The other is to have a global history table (which holds all of your historical data). The structure for such a table normally looks something like
Id bigint not null,
TableName nvarchar(50),
ColumnName nvarchar(50),
PKColumnName nvarchar(50),
PKValue bigint, //or whatever datatype
OriginalValue nvarchar(max),
NewValue nvarchar(max),
ChangeDate datetime
Then you set a trigger on your tables (or, alternatively, add a policy that all of your Updates/Inserts will also insert into your HX table) so that the correct data is logged.

The way we're doing it (might not be the best way) is to have an active bit field, and a foreign key back to the parent record. So for general queries you would filter on active employees, but you can get the history of a single employee with their Employee ID.
declare #employees
(
PK_emID int identity(1,1),
EmployeeID int,
FirstName varchar(50),
LastName varchar(50),
Active bit,
FK_EmployeeID int
primary key(PK_emID)
)
insert into #employees
(
EmployeeID,
FirstName,
LastName,
Active,
FK_EployeeID
)
select 1, 'David', 'Engle', 1,null
union all
select 2, 'Amy', 'Edge', 0,null
union all
select 2, 'Amy','Engle',1,2

Related

Select from a Temp table is giving slow performance

I need some help with the below query where the last step of
Select * from #PersonDetail order by....
is taking so long to execute - why?
There are millions of records being inserted in this temp table #PersonDetail and insert process takes a few seconds, but the last Select from this same temp table is taking so long.
I created a unique clustered index on the columns used for order by and tried many other options but it doesn't make any difference in the performance.
It is a big stored procedure with many temp table but it is this last select step which is impacting the performance. Here is an example of the last step of the query:
DROP TABLE IF EXISTS #PersonDetail
CREATE TABLE #PersonDetail
(
PersonId INT NOT NULL,
Name NVARCHAR(50) NULL,
Number INT NOT NULL,
Tag NVARCHAR(50) NULL,
UserId INT NOT NULL,
NumberEncrypted VARCHAR(100),
Type NVARCHAR(255),
Status NVARCHAR(50),
CreatedDate DATETIMEOFFSET(7),
AddressDetailId NVARCHAR(50),
Category NVARCHAR(50),
PrimaryId INT,
DailyAmount MONEY,
UNIQUE (PersonId UserId),
UNIQUE CLUSTERED(CreatedDate, UserId)
)
INSERT INTO #PersonDetail (PersonId, Name, Number, Tag, UserId, NumberEncrypted,
Type, Status, CreatedDate, AddressDetailId, Category, PrimaryId, Amount)
SELECT
PersonId, Name, Number, Tag, UserId, NumberEncrypted,
Type, Status, CreatedDate, AddressDetailId, Category, PrimaryId, DailyAmount
FROM
#User u
JOIN
dbo.DailyAmount da (NOLOCK) ON da.UserId = u.UserId
SELECT *
FROM #PersonDetail pd
ORDER BY CreatedDate, UserId
You must specify what database are you using.
In general, you must do theese things:
create some indexes on the join columns (DailyAmount.userId, User.userID); how to create the index must change;
create an index on the order by columns, (CreatedDate+UserID); this must change, in postgresql for example an index with the 2 column is better than 2 indexes;
If your data are not changing frequently, you could try materialized view and create the indexes on the materialized view.

How can insert value by selecting from another

I have three tables. table1 for insert data and table2, table3 for selecting data.
table1:
int id,
varchar name,
varchar gender,
varchar category,
table2:
int id,
varchar gender,
table3:
int id,
varchar category,
According to these tables, i'm using stored procedure as below:
Create procedure ABC
(
#id varchar(10),
#name varchar(11),
#gender varchar(10),
#category varchar(10)
)
As
begin
Insert into table1(id, name, gender, category) select #id, #name, g.id, c.id from gender g, category c where g.gender=#gender and c.category=#category
end
Now, using this if gender or category is empty then data is not inserting. Please tell me where i'm wrong and tell best query to insert data using select query. Please help me to solve the problem. Thanks
You are using and in where clause which means only if gender = #gender then it is selecting any record.
Create procedure ABC
(
#id int, ----- change this to int since id is int type in your table
#name varchar(11),
#gender varchar(10)='',
#category varchar(10)=''
)
As
begin
Insert into table1(id, name, gender, category)
select #id, #name, g.id, c.id from gender g, category c
where (g.gender=#gender or isnull(#gender,'')='') and (c.category=#category or isnull(#category,'')='')
end
Although you may use this approach. But since you want to insert id of gender and category column in your table, then on passing null or blank value what is your expected id to be put in your record.
It is better if you first check gender and category value in your respected table and if record not found then insert it in your table and then save its corresponding id in your final table.

Insert values of one table in a database to another table in another database

I would like to take some data from a table from DB1 and insert some of that data to a table in DB2.
How would one proceed to do this?
This is what I've got so far:
CREATE VIEW old_study AS
SELECT *
FROM dblink('dbname=mydb', 'select name,begins,ends from study')
AS t1(name varchar(50), register_start date, register_end date);
/*old_study now contains the data I wanna transfer*/
INSERT INTO studies VALUES (nextval('studiesSequence'),name, '',3, 0, register_start, register_end)
SELECT name, register_start, register_end from old_study;
This is how my table in DB2 looks:
CREATE TABLE studies(
id int8 PRIMARY KEY NOT NULL,
name_string VARCHAR(255) NOT NULL,
description VARCHAR(255),
field int8 REFERENCES options_table(id) NOT NULL,
is_active INTEGER NOT NULL,
register_start DATE NOT NULL,
register_end DATE NOT NULL
);
You should include the column names in both the insert and select:
insert into vip_employees(name, age, occupation)
select name, age, occupation
from employees;
However, your data structure is suspect. Either you should use a flag in employees to identify the "VIP employees". Or you should have a primary key in employees and use this primary key in vip_employees to refer to employees. Copying over the data fields is rarely the right thing to do, especially for columns such as age which are going to change over time. Speaking of that, you normally derive age from the date of birth, rather than storing it directly in a table.
INSERT INTO studies
(
id
,name_string
,description
,field
,is_active
,register_start
,register_end
)
SELECT nextval('studiesSequence')
,NAME
,''
,3
,0
,register_start
,register_end
FROM dblink('dbname=mydb', 'select name,begins,ends from study')
AS t1(NAME VARCHAR(50), register_start DATE, register_end DATE);
You can directly insert values that retured by dblink()(that means no need to create a view)
Loop and cursor are weapons of last resort. Try to avoid them. You probably want INSERT INTO ... SELECT:
INSERT INTO x(x, y, z)
SELECT x, y, z
FROM t;
SqlFiddleDemo
EDIT:
INSERT INTO vip_employees(name, age, occupation) -- your column list may vary
SELECT name, age, occupation
FROM employees;
Your syntax is wrong. You cannot have both, a values clause for constant values and a select clause for a query in your INSERT statement.
You'd have to select constant values in your query:
insert into studies
(
id,
name_string,
description,
field,
is_active,
register_start,
register_end
)
select
studiesSequence.nextval,
name,
'Test',
null,
0,
register_start,
register_end
from old_study;

Delete duplicate rows with soundex?

I have two tables, one has foreign keys to the other. I want to delete duplicates from Table 1 at the same time updating the keys on Table 2. I.e count the duplicates on Table 1 keep 1 key from the duplicates and query the rest of the duplicate records on Table 2 replacing them with the key I'm keeping from Table 1. Soundex would be the best option because not all the names are spelled right in Table 1. I have the basic algorithm but not sure how to do it. Help?
So far this is what I have:
declare #Duplicate int
declare #OriginalKey int
create table #tempTable1
(
CourseID int, <--- The Key I want to keep or delete
SchoolID int,
CourseName nvarchar(100),
Category nvarchar(100),
IsReqThisYear bit,
yearrequired int
);
create table #tempTable2
(
CertID int,
UserID int,
CourseID int, <---- Must stay updated with Table 1
SchoolID int,
StartDateOfCourse datetime,
EndDateOfCourse datetime,
Type nvarchar(100),
HrsOfClass float,
Category nvarchar(100),
Cost money,
PassFail varchar(20),
Comments nvarchar(1024),
ExpiryDate datetime,
Instructor nvarchar(200),
Level nchar(10)
)
--Deletes records from Table 1 not used in Table 2--
delete from Table1
where CourseID not in (select CourseID from Table2 where CourseID is not null)
insert into #tempTable1(CourseID, SchoolID, CourseName, Category, IsReqThisYear, yearrequired)
select CourseID, SchoolID, CourseName, Category, IsReqThisYear, yearrequired from Table1
insert into #tempTable2(CertID, UserID, CourseID, SchoolID, StartDateOfCourse, EndDateOfCourse, Type, HrsOfClass,Category, Cost, PassFail, Comments, ExpiryDate, Instructor, Level)
select CertID, UserID, CourseID, SchoolID, StartDateOfCourse, EndDateOfCourse, Type, HrsOfClass,Category, Cost, PassFail, Comments, ExpiryDate, Instructor, Level from Table2
select cour.CourseName, Count(cour.CourseName) cnt from Table1 as cour
join #tempTable1 as temp on cour.CourseID = temp.CourseID
where SOUNDEX(temp.CourseName) = SOUNDEX(cour.CourseName) <---
The last part does not exactly work, gives me an error
Error: Column 'Table1.CourseName' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
UPDATE: Some of the names in CourseName have numbers in them too. Like some are in romans and numeral format. Need to find those too but Soundex ignores numbers.

How do I populate the identity column when inserting into a table?

I have a table whose data is inserted by selecting from another table. For example,
CREATE TABLE TestTable (ID int, FirstName VARCHAR(100), LastName VARCHAR(100))
INSERT INTO TestTable (FirstName, LastName)
SELECT FirstName, LastName
FROM Person.Contact
But How do I populate the ID? I tried
INSERT INTO TestTable (SCOPE_IDENTITY()+1, FirstName, LastName)
SELECT FirstName, LastName
FROM Person.Contact
I don't want to make ID as identity column is because I duplicate the table structure from an exsiting one which the ID is regular column.
But it doesn't work. Any idea?
This depends on the exact SQL server you're using, but since it appears you're using Microsoft SQL Server:
Simply labeling your column as ID is not enough. You'll need to make sure that the ID column is marked in SQL Server as an Identity column. This is similar to marking a column SERIAL in PostgreSQL, or AUTOINCREMENT in MySQL. Make sure you've done this first.
Assuming you've done that, simply let the database itself add the identity value by explicitly not referencing that column in your INSERT statement. Thus, something like
INSERT INTO TestTable (FirstName, LastName)
SELECT FirstName, LastName
FROM Person.Contact
and relying on SQL Server's underlying identity support to fill it in for you will work fine. It looks from your example like the thing you're missing is marking the ID column as an identity column in the first place.
They are right in that you should specify a autonumber column. As below:
CREATE TABLE TestTable
(
ID int NOT NULL IDENTITY (1, 1),
Firstname varchar(100) NULL,
Lastname varchar(100) NULL
)
Then when you insert, use the following:
DECLARE #MyTableVar table( ID int);
INSERT INTO TestTable
OUTPUT INSERTED.ID
INTO #MyTableVar
SELECT FirstName, LastName
FROM Person.Contact;
Then you select #MyTableVar for the identities you inserted
Is below what you are looking for?
SELECT
id + 0
,FirstName
,LastName
INTO test_table
From Person.Contact