Ενας τρόπος να το κάνεις είναι ο παρακάτω (σε SQL Server 2000, προφανώς όμως ισχύει και για 2005):
Ας υποθέσουμε οτι όλα τα πεδία a,b,c,d,e,f των p1, p2 είναι τύπου int για ευκολία. Επίσης ας υποθέσουμε (δεν παίζει ρόλο στο τέλος, απλά για το παράδειγμα) οτι τα primary keys a και d είναι identity (autonumber) πεδία.
Ας κατασκευάσουμε τον πίνακα p1:
CREATE TABLE [dbo].[p1] (
a [int] IDENTITY (1, 1) NOT NULL ,
b [int] NULL ,
c [int] NULL
) ON [PRIMARY]
GO
(Σημείωση: Για να μην γίνει τεράστιο το post δεν βάζω και τα primary key constraints μια και δεν αφορούν το συγκεκριμένο θέμα)
Εφόσον το c δεν έχει τίποτα επάνω του, ο μόνος τρόπος για να πάρουμε τις τιμές που περιέχει το C μοναδικά είναι να κάνουμε ένα
SELECT DINSTINCT p1.c FROM p1
Ετσι λοιπόν θα μπορούσαμε δυνητικά να κατασκευάσουμε τον δεύτερο πίνακα (που έχει τον έλεγχο στο πεδίο f) ως εξής:
CREATE TABLE [dbo].[p2] (
d [int] IDENTITY (1, 1) NOT NULL ,
e [int] NULL ,
f [int] NULL
check (f in (SELECT DISTINCT p1.c FROM p1))
) ON [PRIMARY]
GO
Αλλα αυτό δεν παίζει! Θα πάρουμε τα εξής μηνύματα:
Subqueries are not supported in CHECK constraints, table 'dbo.p2'.
Column CHECK constraint for column 'f' references another column, table 'dbo.p2'.
Invalid column 'c' is specified in a constraint or computed-column definition.
Could not create constraint. See previous errors.
Και είναι φυσικό, μια και "Subqueries are not supported in CHECK constraints". Αρα πρέπει να βρούμε έναν άλλο τρόπο να κάνουμε τη δουλειά μας. Ετσι, μπορούμε να φτιάξουμε μια UDF (user-defined function) ως εξής:
CREATE FUNCTION [dbo].[myCheck] (@myparam int)
RETURNS bit
AS
BEGIN
DECLARE @retVal bit
IF EXISTS (SELECT DISTINCT p1.c FROM p1 WHERE p1.c = @myparam)
BEGIN
SET @retVal =1
END
ELSE
BEGIN
SET @retVal =0
END
RETURN @retVal
END
Η οποία θα δέχεται ως παράμετρο μια τιμή και θα μας γυρνάει 1 αν η τιμή υπάρχει στο p1.c πεδίο ή 0 αν δεν υπάρχει. Φυσικά, η τιμή που θα της περνάμε θα είναι η τιμή του πεδίου f.
Για να τη χρησιμοποιήσουμε στο CHECK constraint μας, φτιάχνουμε τον πίνακα p2 ως εξής:
CREATE TABLE [dbo].[p2] (
d [int] IDENTITY (1, 1) NOT NULL ,
e [int] NULL ,
f [int] NULL
check (dbo.myCheck(f)=1)
) ON [PRIMARY]
GO
Με το check (dbo.myCheck(f)=1), σε κάθε εγγραφή που γίνεται insert ή update στον πίνακα p2 ελέγχεται μέσω της udf η τιμή του f για το αν υπάρχει στο πεδίο c του πίνακα p1.
Φυσικά, όπως ανέφερα, αυτός είναι ο ένας τρόπος. Ο άλλος τρόπος είναι με τη χρήση triggers. Σταματάω όμως εδώ για τώρα μια και είναι αρκετά αργά :) Ελπίζω να μην σε μπέρδεψα πολύ!
Σωτήρης Φιλιππίδης
DotSee Web Services