Relations between Table and View using Microsoft SQL - sql-server

Is there a natural option to establish a relationship between table and view or i should use trigger as a workaround to check that the data consistency?
I have a lookup view (for some reason i need it to be view and not a table).
I want to insert records to a different table. one of the values of the record i want to insert MUST be one of the ids from the lookup view.
For example:
ViewCities (CityId, CityName) -- This is the lookup View. the table behind the view located on a different database.
now i want to insert new row to tblUsers. one of the row columns is CityId. I want that not one will be able to insert a row to tblUsers that includes cityid that not exists on ViewCities.

You have two options that I am aware of to maintain referential integrity. You cannot use a foreign key constraint because you said that the tables are in two separate databases. The options are:
1. Use triggers, as you had mentioned.
2. Use a check constraint which references a user defined function which does the check.
For example:
Let's say I have a database named test, and another database is the Northwind database. In my test database I want to create a table which records names of users. The check I want to enforce is that the user name must be one of the LastName's of a user in the Northwind database. I first create a UDF like so:
create function chk_name (#name varchar(50))
returns bit
as
begin
declare #name_found bit=0
if exists(select * from Northwind..Employees where LastName=#name)
begin
set #name_found=1
end
return #name_found
end
Then, I create the table with a check constraint like so:
create table tst
(name varchar(50) check ( dbo.chk_name(name)=1 )
)
Now, if you try to insert a row into the tst table, it must be one of the Last Names of the Employees table in the Northwind database.

Related

How can split a row of data and insert each row (but different columns) into two tables (with a FK relationship) in SSIS?

I have two tables in SQL Server:
Person
ID (PK, int, IDENTITY)
Name (varchar(100))
UploadedBy (varchar(50))
DateAdded (datetime)
PersonFile
ID (PK, int, IDENTITY)
PersonId (FK, int)
PersonFile (varchar(max))
I am reading in a large file (150MB), and I have a script component that can successfully parse the file into several columns. The issue is that I need to insert the first 3 columns of my parsed data row into my Person table first, then use the ID of that Row to insert the final column into my PersonFile table. Is there an easy way to do this in SSIS?
I suppose I could technically script everything out to handle inserts in the database, but I feel like in that case, I might as well just skip SSIS altogether and user powershell. I also thought about writing a procedure in SQL server and then passing the information to the procedure to handle inserts. But again, this seems very inefficient.
What's the best way for me to insert a row of data into two tables, if one of them has a foreign key constraint?
I think the best way is to use a stage table in the database to hold the parsed source file and then use stored procedures or SQL-query to load your tables. There is a lookup component in SSIS that can be used for your case but I try avoiding it for various reasons.
Create a table resembeling the source file, something like:
CREATE TABLE dbo.[SourceFileName](
Name nvarchar(100) NULL,
UploadedBy nvarchar(50) NULL,
DateAdded datetime NULL,
PersonFile nvarchar(max) NULL
)
Truncate the stage table. Use a dataflow component to get the source data. Use script or stored procedures to insert the source data in your destination table (begin with Person and the load PersonFile). Your SSIS dataflow should look something like this:
For the insert script for person do something like:
INSERT INTO dbo.Person (Name, UploadedBy,DateAdded)
SELECT Name,UploadedBy,DateAdded
FROM dbo.SourceFileName;
For the insert for PersonFile make a join to the destination table:
INSERT INTO dbo.PersonFile(PersonId,PersonFile)
SELECT
Person.ID,
SourceFile.PersonFile
FROM dbo.SourceFileName SourceFile
JOIN dbo.Person Person
ON Person.Name = SourceFile.Name
You should also add a UNIQUE CONSTRAINT to the column that identifies the person (Name for example).
One very common thing to do would be to stage the data first.
So you insert all columns into a table on the server, which also has an extra nullable column for the PersonID.
Then you’d have a stored procedure which inserts unique Person records into the Person table, and updates the staging table with the resulting PersonID, which is the extra field you need for the PersonFile insert, which could then be performed either in the same procedure or another one. (You’d call these procedures in SSIS with an Execute SQL Task.)
I suppose this could possibly be done purely in SSIS, for example with a Script Destination that performs an insert and retrieves the PersonID for a second insert, but I’m fairly sure performance would take a huge hit with an approach like that.

How to copy one database to another database in sql server when tables and constraints already exist in the target database?

I had created identical databases in different environments: Dev and QA. While doing the development, I have changed a few tables in the Dev database. How do I change the QA database to make it again identical to the Dev database in terms of tables (and constraints)?
I checked the below link:
[Copy one database to another database
Steps in the above link did not directly work because the tables and constraints already existed in the second database. I did modification in the sql file after the steps
I followed the below steps:
Right-click on the database you want to copy
Choose 'Tasks' > 'Generate scripts'
'Select specific database objects' and Check 'Tables'
Click on Next. Again click on Next.
This exports .sql file to the path shown while following the above steps.
I edited the script file and changed the database name to the QA database name (at the top of the script).
After this added the below line above every create table statement as the table exist.
DROP TABLE IF EXISTS tablename;
On running the query, I get an error message saying
Could not drop object tablename because it is referenced by a FOREIGN
KEY constraint.
How do I change the second database to make it identical to the first database in terms of tables (and constraints)?
Thank You
Well, the most straight forward solution would be to drop all constraints first. You could add a drop constraint per constraint above your drop table lines, though that may be tedious.
An answer to this question has a script that drops every constraint in a database and table. You could omit the table name param in the where.
But, since you're destroying everything in the database, it might be easiest to delete and recreate the database. Then you wouldn't need to add the drop table statements to the create script from dev.
In your scripts, separate tables creation, from insertion of records, for later.
Example (before):
create table one ...
insert into table one ...
create table two ...
insert into table two ..
create table three ...
insert into table three ..
Example (after)
create table one ...
create table two ...
create table three ...
insert into table one ...
insert into table two ..
insert into table three ..
If you have foreign constraints, check that the destination tables (primary table or master table), are created and filled first, than the source tables (secondary table or slave table).
Example (before):
create table one
(int onekey primary key, int threekey foreing key)
create table three ...
(int threekey primary key)
insert into table one ...
insert into table three ..
Example (after):
create table three ...
(int threekey primary key)
create table one
(int onekey primary key, int threekey foreing key)
insert into table three ..
insert into table one ...
And, finally, if you use automatic of self generated keys, turn off before table insertion, and turn on back, after table insertion, because the DB server may assign new keys to destination tables, and source tables, may expect the previous keys.

Which are the simplest way to do cross database references in pgAdmin?

I want to do horizontal fragmentation on a table say table employee(attributes) which is in 'Employee' database on 'server1' and such fragments are need to store in table on other databases on same server. For doing this I am currently using rules so that changes can be replicated. For example if some insert happens on one of the fragment then those inserted values should also must get stored on main table. So I need to write cross database referencing queries for this. Can anyone tell me how to write such queries in pgAdmin , specially for creating rules for ex:
CREATE RULE employee1 AS
ON INSERT TO employee WHERE
( dno BETWEEN 1 AND 10 )
DO INSTEAD
INSERT INTO employee1 VALUES ( NEW.eno, NEW.ename, NEW.title, NEW.dno );
where table employee and employee1 resides on different database but on same server.

Best way to move data between tables and generate mapping of old to new identity values

I need to merge data from 2 tables into a third (all having the same schema) and generate a mapping of old identity values to new ones. The obvious approach is to loop through the source tables using a cursor, inserting the old and new identity values along the way. Is there a better (possibly set-oriented) way to do this?
UPDATE: One additional bit of info: the destination table already has data.
Create your mapping table with an IDENTITY column for the new ID. Insert from your source tables into this table, creating your mapping.
SET IDENTITY_INSERT ON for your target table.
Insert into the target table from your source tables joined to the mapping table, then SET IDENTITY_INSERT OFF.
I created a mapping table based on the OUTPUT clause of the MERGE statement. No IDENTITY_INSERT required.
In the example below, there is RecordImportQueue and RecordDataImportQueue, and RecordDataImportQueue.RecordID is a FK to RecordImportQueue.RecordID. The data in these staging tables needs to go to Record and RecordData, and FK must be preserved.
RecordImportQueue to Record is done using a MERGE statement, producing a mapping table from its OUTPUT, and RecordDataImportQueue goes to RecordData using an INSERT from a SELECT of the source table joined to the mapping table.
DECLARE #MappingTable table ([NewRecordID] [bigint],[OldRecordID] [bigint])
MERGE [dbo].[Record] AS target
USING (SELECT [InstanceID]
,RecordID AS RecordID_Original
,[Status]
FROM [RecordImportQueue]
) AS source
ON (target.RecordID = NULL) -- can never match as RecordID is IDENTITY NOT NULL.
WHEN NOT MATCHED THEN
INSERT ([InstanceID],[Status])
VALUES (source.[InstanceID],source.[Status])
OUTPUT inserted.RecordID, source.RecordID_Original INTO #MappingTable;
After that, you can insert the records in a referencing table as folows:
INSERT INTO [dbo].[RecordData]
([InstanceID]
,[RecordID]
,[Status])
SELECT [InstanceID]
,mt.NewRecordID -- the new RecordID from the mappingtable
,[Status]
FROM [dbo].[RecordDataImportQueue] AS rdiq
JOIN #MappingTable AS mt
ON rdiq.RecordID = mt.OldRecordID
Although long after the original post, I hope this can help other people, and I'm curious for any feedback.
I think I would temporarily add an extra column to the new table to hold the old ID. Once your inserts are complete, you can extract the mapping into another table and drop the column.

How do I add the identity property to an existing column in SQL Server

In SQL Server (in my case, 2005) how can I add the identity property to an existing table column using T-SQL?
Something like:
alter table tblFoo
alter column bar identity(1,1)
I don't beleive you can do that. Your best bet is to create a new identity column and copy the data over using an identity insert command (if you indeed want to keep the old values).
Here is a decent article describing the process in detail:
http://www.mssqltips.com/tip.asp?tip=1397
The solution posted by Vikash doesn't work; it produces an "Incorrect syntax" error in SQL Management Studio (2005, as the OP specified). The fact that the "Compact Edition" of SQL Server supports this kind of operation is just a shortcut, because the real process is more like what Robert & JohnFX said--creating a duplicate table, populating the data, renaming the original & new tables appropriately.
If you want to keep the values that already exist in the field that needs to be an identity, you could do something like this:
CREATE TABLE tname2 (etc.)
INSERT INTO tname2 FROM tname1
DROP TABLE tname1
CREATE TABLE tname1 (with IDENTITY specified)
SET IDENTITY_INSERT tname1 ON
INSERT INTO tname1 FROM tname2
SET IDENTITY_INSERT tname1 OFF
DROP tname2
Of course, dropping and re-creating a table (tname1) that is used by live code is NOT recommended! :)
Is the table populated? If not drop and recreate the table.
If it is populated what values already exist in the column? If they are values you don't want to keep.
Create a new table as you desire it, load the records from your old table into your new talbe and let the database populate the identity column as normal. Rename your original table and rename the new one to the correct name :).
Finally if the column you wish to make identity currently contains primary key values and is being referenced already by other tables you will need to totally re think if you're sure this is what you want to do :)
There is no direct way of doing this except:
A) through SQL i.e.:
-- make sure you have the correct CREATE TABLE script ready with IDENTITY
SELECT * INTO abcTable_copy FROM abcTable
DROP TABLE abcTable
CREATE TABLE abcTable -- this time with the IDENTITY column
SET IDENTITY_INSERT abcTable ON
INSERT INTO abcTable (..specify all columns!) FROM (..specify all columns!) abcTable_copy
SET INDENTITY_INSERT abcTable OFF
DROP TABLE abcTable_copy
-- I would suggest to verify the contents of both tables
-- before dropping the copy table
B) Through MSSMS which will do exactly the same in the background but will less fat-fingering.
In the MSSMS Object Explorer right click the table you need to modify
Select "design" Select the column you'd like to add IDENTITY to
Change the identity setting from NO -> YES (possibly seed)
Ctr+S the table
This will drop and recreate the table with all original data in it.
If you get a warning:
Go to MSSMS Tools -> Options -> Designers -> Table and database Designers
and uncheck the option "Prevent saving changes that require table re-creation"
Things to be careful about:
your DB has enough disk space before you do this
the DB is not in use (especially the table you are changing)
make sure to backup your DB before doing it
if the table has a lot of data (over 1G) try it somewhere else first
before using in real DB
Create a New Table
SELECT * INTO Table_New FROM Table_Current WHERE 1 = 0;
Drop Column from New Table
Alter table Table_New drop column id;
Add column with identity
Alter table Table_New add id int primary key identity;
Get All Data in New Table
SET IDENTITY_INSERT Table_New ON;
INSERT INTO Table_New (id, Name,CreatedDate,Modified)
SELECT id, Name,CreatedDate,Modified FROM Table_Current;
SET IDENTITY_INSERT Table_New OFF;
Drop old Table
drop table Table_Current;
Rename New Table as old One
EXEC sp_rename 'Table_New', 'Table_Current';
alter table tablename
alter column columnname
add Identity(100,1)

Resources