I have a table, Contacts, with a primary key of ContactID, which is an identity column. I have another table, Person, with a primary key of PersonID that is a foreign key to ContactID. When I insert a record into Person, I would like PersonID to pull the corresponding identity from ContactID in Contact.
In Access, I simply make a query that references both tables, and it will fill in the foreign key column with the corresponding value in the identity (autonumber) column.
SELECT Person.PersonID, Person.FirstName, Person.MiddleName, Person.LastName, Contact.ContactID, Contact.EmailAddress, Contact.PhoneNumber
FROM (Contact INNER JOIN Person ON Contact.ContactID = Person.PersonID);
How can we achieve this in SQLServer 2008 R2? I have been programming triggers to update the keys, but it seems like there ought to be a better way.
Thank you very much for your assistance.
When you insert to the first table, you use the OUTPUT clause to pull the identity value and then you can use it to insert to the child table.
You can also use scope_identity() to do the same thing, but OUTPUT is the preferred method. Do not under any circumstances use ##Identity as it often will give incorrect results and mess up your data integrity.
Look up how to use them in Books Online.
Related
I have a problem to set correct constraint to make sure one column has and only has one matched column within the table.
For example, company Apple has Bloomberg ticker AAPL:US and only has this ticker. Otherwise, SQL Server will notice there is a error.
I try to use constraint with unique, but it does not work.
I imagine that your schema might be a standard one using a junction table. That is, your tables might look something like:
company (id, name)
ticker (id, name)
company_ticker (id_company, id_ticker)
That is, the company_ticker table is a junction table which stores the relationships between companies and tickers. Normally, this table would by default be many-to-many. But if you want to restrict a company to having only one ticker, then you may place a unique constraint on the id_company column:
CREATE TABLE company_ticker (
id_company INT NOT NULL,
id_ticker INT NOT NULL,
PRIMARY KEY (id_company, id_ticker),
CONSTRAINT cnstr UNIQUE (id_company)
);
With the above unique constraint in place, your schema will only allow a given company to have one relationship with some ticker.
I have a data table with a primary key called OptDefID. When a record in this table is deleted I need to go and delete all records from the Permissions table that have that OptDefID in the defID field (in Permissions). The tricky part for me is that the Permissions table does not have a primary key and holds lots of different kinds of permissions, and has a permissiontype field. I need to delete rows that have the OptDefID AND a permissiontype of OptDef.
Because I need to consider the permissiontype, I don't believe a Foreign Key Constraint is appropriate here (or is it?).
I've also considered creating a trigger, but am unsure how to get the OptDefID passed into the trigger.
I can do this via the application itself, but I feel like this should be a database level solution.
What's the best solution?
Say I want to delete from Permissions where defID is 20 and permissiontype is 'OptDef'. There may be another row in Permissions that has a defID of 20, but has a permissiontype of 'Member'. That show should not be deleted because it pertains to Members and not Opt data.
Storing table names in fields prevents foreign keys from working properly, as you have discovered.
I recommend you fix the root problem and separate these two foreign keys, so each of them can be individually enforced. For example:
CREATE TABLE Permissions (
...
OptDefId int,
MemberId int,
FOREIGN KEY (OptDefId) REFERENCES OptDef ON DELETE CASCADE,
FOREIGN KEY (MemberId) REFERENCES Members ON DELETE CASCADE,
CHECK (
(OptDefId IS NOT NULL AND MemberId IS NULL)
OR (OptDefId IS NULL AND MemberId IS NOT NULL)
)
)
The CHECK makes sure only one of the FKs is non-NULL and only non-NULL FKs are enforced.
Alternatively, you could avoid changing your current design and enforce this "special" FK through a trigger, but declarative constraints should be preferred to triggers when possible - declarative constraints tend to leave less room for error and be more "self-documenting".
In case the OptDefId column is only filled when the record in question references the Permissions table, a foreign key should be appropriate. I.e. you have another column MemberId, which in turn could be a foreign key on a Members table.
It is only when you have a single column - let's call it ObjectId - which takes on other meanings as the contents of the type column change, that you cannot use foreign keys.
In that case, a trigger would probably be the best approach, as you already guessed. I only know about triggers in Oracle PL/SQL, where they are passed in as separate, complete rows representing the old and new state. I guess it will be analogous in MS-SQL-Server.
In addition to using join with SELECT statements, you can also join multiple tables in DELETE & UPDATE statements as well.
As I understand the issue, you should be able to join the Permissions table to the table with the OptDefID column & add a WHERE clause similar to the this:
DELETE MyTable
...
WHERE [Permissions].permissiontype = 'OptDef'
Also, these links may be of interest too:
SQL DELETE with JOIN another table for WHERE condition (for MySQL, but still relevant)
Using A SQL JOIN In A SQL DELETE Statement
Using A SQL JOIN In A SQL UPDATE Statement
I was trying to create a table that has a one to many relationships. but it seems that adding a foreign key in Personal is not working. I am trying to link a Personal Information table to a address table? what is the solution for this error?
Address table saved successfully
Personal table
Unable to create relationship 'FK_Personal_Address'.
Cascading foreign key 'FK_Personal_Address' cannot be created where the
referencing column 'Personal.ID' is an identity column. Could not
create constraint. See previous errors.
The primary key in the Person table is presumably an identity. This is an auto-incrementing integer field.
You need to make the foreign key in the address table of type int, not identity. It will hold integers which correspond to Person records, but you don't want the foreign key to auto-increment. For each record in the child table (address) you will set a specific value for the foreign key indicating to which parent record (Person) it belongs.
Example:
INSERT person (firstname, lastname) VALUES ('John', 'Smith')
This will insert the new person record and the field personid will be filled automatically because it is an IDENTITYfield.
Now to insert an address from John Smith you need to know his personid. For example:
-- Say, for example, personid of John Smith is 55
INSERT address (personid, street, city) VALUES (55, 'High Street', 'London')
So in the person table the personid is generated automatically but in the address table you specify the value that matches an existing person. That's the whole point of a foreign key.
Without more information about your schema it's hard to guess the problem.
I made sure to follow identity, int and primary key discussed in above answer. However, I was still getting the same error.
'xReason' table saved successfully
'xAddress' table
- Unable to create relationship 'FK_xAddress_xReason'.
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_xAddress_xReason". The conflict occurred in database "databaseName", table "dbo.xReason", column 'xReasonID'.
This error resolved when I inserted some data into a Reason table. (table that had a primary key)
If you read this far, this might be your problem.
Without seeing the structure of the tables in the question, I believe the most likely cause is the column in your child table (Address) is marked as an Identity column. In a foreign-key relationship, the parent determines the value of the field, not the child. The column may be the PK in the child table, but not an Identity.
it seem that you try to create a foreign key on Personal.ID related to itself.
You probably want to do something like :
ALTER TABLE Adress WITH NOCHECK ADD CONSTRAINT [FK_Adress_Personnal] FOREIGN KEY(Personal_Id)
REFERENCES Personal (ID)
I got the same error with adding foreign key constraints to one of my tables.
I found the workaround was to add it WITH NOCHECK. why I was able to add the other two foreign keys WITH CHECK but not the third foreign? I found that it was not the table but the order of the foreign key to be added. Any insight to this will be much appreciated.
I have three tables: Employee, Emp_Address and Emp_AddressDetail.
Employee table is master and Emp_Address is detail.
Emp_Address is master and Emp_AddressDetail is detail.
I want to copy all rows from a table to another table.
How can I do it?
If I understand your question correct you want to insert data from one table to another? If so, you should have a look at the INTO statement. http://msdn.microsoft.com/en-us/library/ms188029.aspx
SELECT * INTO dbo.OneTable FROM Production.AnotherTable
If the tables have foreign keys defined, and those foreign key definitions need to be set on the new database, than you need to take a look at the data diagrams, and identify any tables that do not have foreign key columns. In your case the copy order will be Employee, Emp_Address, Emp_AddressDetail
If you do not have explicit SQL Server maintained foreign keys, or if the foreign keys are not set on the target database, you can just copy the data in any order you like.
Note that it's entirely possible to paint yourself into a corner, e.g. if there was field in the Employee table called PrimaryAddress that would be a foreign key to the Emp_Address table.
I want to create a DB , where each table's PK will be GUID and which will be unique across the DB,
Example: my DB name is 'LOCATION'. And I have 3 table as 'CITY' , 'STATE' and 'COUNTRY'.
I want that all the 3 tables have same PK field as GUID ,and that value will be unique across DB.
How to do this in SQL Server, any idea? I have never used SQL Server before, so it will be helpful if briefly explained.
create table CITY (
ID uniqueidentifier not null primary key default newid(),
.
.
.
)
Repeat for the other tables.
What do you mean exactly ?
Just create the table, add an Id field to each table, set the data type of the Id field to 'uniqueidentifier', and you're good to go.
Next, add a primary constraint on those columns, and make sure that, when inserting a new record you assign a new guid to that column (for instance, by using the newid() function).
I can't think of any good reason to have a unique number shared by 3 tables, why not just give each table a unique index with a foreign key reference? Indexed fields are queried quicker than random numbers would be.
I would create a 'Location' table with foreign keys CityId, StateId & CountryId to link them logically.
edit:
If you are adding a unique id across the City, State and Country tables then why not just have them as fields in the same table? I would have thought that your reason for splitting them into 3 tables was to reduce duplication in the database.