I am getting following error when deleting a column with constraint in SQL Server 2005.
The object 'DF__PlantRecon__Test' is dependent on column 'Test'.
The column is not part of any key. But it has a default constraint and the constraint has a pre-defined name.
Though I have written code to delete constraint first, it is not working.
Why doesn't it work?
What need to be done to make it working?
Note: I need to check whether the constraint exist first.
REFERENCES
Named CONSTRAINT benefits
How to drop column with constraint?
How to drop SQL default constraint without knowing its name?
CODE
IF OBJECT_ID('DF__PlantRecon__Test', 'C') IS NOT NULL
BEGIN
SELECT 'EXIST'
ALTER TABLE [dbo].[PlantReconciliationOptions] drop constraint DF__PlantRecon__Test
END
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS WHERE CONSTRAINT_NAME ='DF__PlantRecon__Test')
BEGIN
SELECT 'EXIST'
--drop constraint
ALTER TABLE [dbo].[PlantReconciliationOptions] drop constraint DF__PlantRecon__Test
END
IF EXISTS ( SELECT * FROM sys.columns WHERE object_id = OBJECT_ID(N'[dbo].[PlantReconciliationOptions]') AND name = 'Test')
BEGIN
--drop column
ALTER TABLE [dbo].[PlantReconciliationOptions] DROP COLUMN Test
END
ALTER TABLE PlantReconciliationOptions
ADD Test INT NOT NULL
CONSTRAINT DF__PlantRecon__Test DEFAULT 30
try
IF OBJECT_ID('DF__PlantRecon__Test') IS NOT NULL
BEGIN
SELECT 'EXIST'
ALTER TABLE [dbo].[PlantReconciliationOptions] drop constraint DF__PlantRecon__Test
END
In your example, you were looking for a 'C' Check Constraint, which the DEFAULT was not. You could have changed the 'C' for a 'D' or omit the parameter all together.
If you are consistent with your naming, as it appears you are, (e.g. DF__xxx) then dropping the second parameter is an acceptable choice to be sure that the hard coded constraint name is dropped.
Here is a list of the OBJECT_ID() Object Types you can pass:
AF = Aggregate function (CLR)
C = CHECK constraint
D = DEFAULT (constraint or stand-alone)
F = FOREIGN KEY constraint
PK = PRIMARY KEY constraint
P = SQL stored procedure
PC = Assembly (CLR) stored procedure
FN = SQL scalar function
FS = Assembly (CLR) scalar function
FT = Assembly (CLR) table-valued function
R = Rule (old-style, stand-alone)
RF = Replication-filter-procedure
S = System base table
SN = Synonym
SQ = Service queue
TA = Assembly (CLR) DML trigger
TR = SQL DML trigger
IF = SQL inline table-valued function
TF = SQL table-valued-function
U = Table (user-defined)
UQ = UNIQUE constraint
V = View
X = Extended stored procedure
IT = Internal table
(This list was found on Beyond Relational: Using TSQL Function: OBJECT_ID())
Steps to solve your problem.
Open SSMS.
Edit the table to remove the default. Do not press save
Script the output to "new window".
Read the script.
Related
So I have a query that should add Primary Key to the Id field:
IF NOT EXISTS(SELECT *
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = 'CAL')
BEGIN
DROP INDEX IF EXISTS CAL$01 ON dbo.CAL;
ALTER TABLE BTS.dbo.CAL
ALTER COLUMN Intern INT NOT NULL;
ALTER TABLE BTS.dbo.CAL
ADD CONSTRAINT PK_CAL_Intern PRIMARY KEY (Intern);
CREATE INDEX CAL$01
ON CAL (Intern);
END
The problem is that when I chose all this code and execute (F5), I get this error:
Whereas when I'm choosing every statement one by one it works as expected:
I am sure that the IF works as expected
I tried to use GO between statements, it's not allowed.
I should execute this code on a large number of tables
Maybe I don't know something about how SQL Server Management Studio executes statements
Before a query is run it is parsed. This is why what you're doing is failing. SQL server is checking the details of the Intern before the script is run. At the point you start to try to run the script, Intern in the table BTS.dbo.CAL is NULLable, and so the script fails.
You can get around this by running the statement to create the primary key cosntraint in a separate scope:
IF NOT EXISTS(
SELECT *
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS
WHERE CONSTRAINT_TYPE = 'PRIMARY KEY' AND TABLE_NAME = 'CAL'
)
BEGIN
DROP INDEX IF EXISTS CAL$01 ON dbo.CAL;
ALTER TABLE
BTS.dbo.CAL
ALTER COLUMN
Intern
INT NOT NULL;
EXEC sys.sp_executesql N'ALTER TABLE BTS.dbo.CAL ADD CONSTRAINT PK_CAL_Intern PRIMARY KEY (Intern);';
CREATE INDEX [CAL$01]
ON CAL (Intern);
END'
Even though question is answer, I just wanted to add one more option.
You can separate statments into two separate batches, so that your change is available to the subsequent batch
CREATE TABLE #test(a int null);
-- DDL Changes
if exists(SELECT 1)
BEGIN
ALTER TABLE #test ALTER COLUMN a int not null;
END
GO
-- Index changes
if exists(SELECT 1)
BEGIN
ALTER TABLE #test ADD CONSTRAINT PK_test PRIMARY KEY(a)
END
GO
I am trying to do this:
ALTER TABLE CompanyTransactions DROP COLUMN Created
But I get this:
Msg 5074, Level 16, State 1, Line 2
The object 'DF__CompanyTr__Creat__0CDAE408' is dependent on column 'Created'.
Msg 4922, Level 16, State 9, Line 2
ALTER TABLE DROP COLUMN Created failed because one or more objects access this column.
This is a code first table. Somehow the migrations have become all messed up and I am trying to manually roll back some changed.
I have no idea what this is:
DF__CompanyTr__Creat__0CDAE408
You must remove the constraints from the column before removing the column. The name you are referencing is a default constraint.
e.g.
alter table CompanyTransactions drop constraint [df__CompanyTr__Creat__0cdae408];
alter table CompanyTransactions drop column [Created];
The #SqlZim's answer is correct but just to explain why this possibly have happened. I've had similar issue and this was caused by very innocent thing: adding default value to a column
ALTER TABLE MySchema.MyTable ADD
MyColumn int DEFAULT NULL;
But in the realm of MS SQL Server a default value on a colum is a CONSTRAINT. And like every constraint it has an identifier. And you cannot drop a column if it is used in a CONSTRAINT.
So what you can actually do avoid this kind of problems is always give your default constraints a explicit name, for example:
ALTER TABLE MySchema.MyTable ADD
MyColumn int NULL,
CONSTRAINT DF_MyTable_MyColumn DEFAULT NULL FOR MyColumn;
You'll still have to drop the constraint before dropping the column, but you will at least know its name up front.
As already written in answers you need to drop constraints (created automatically by sql) related to all columns that you are trying to delete.
Perform followings steps to do the needful.
Get Name of all Constraints using sp_helpconstraint which is a system stored procedure utility - execute following exec sp_helpconstraint '<your table name>'
Once you get the name of the constraint then copy that constraint name and execute next statement i.e alter table <your_table_name>
drop constraint <constraint_name_that_you_copied_in_1> (It'll be something like this only or similar format)
Once you delete the constraint then you can delete 1 or more columns by using conventional method i.e Alter table <YourTableName> Drop column column1, column2 etc
When you alter column datatype you need to change constraint key for every database
alter table CompanyTransactions drop constraint [df__CompanyTr__Creat__0cdae408];
You need to do a few things:
You first need to check if the constrain exits in the information schema
then you need to query by joining the sys.default_constraints and sys.columns
if the columns and default_constraints have the same object ids
When you join in step 2, you would get the constraint name from default_constraints. You drop that constraint. Here is an example of one such drops I did.
-- 1. Remove constraint and drop column
IF EXISTS(SELECT *
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = N'TABLE_NAME'
AND COLUMN_NAME = N'LOWER_LIMIT')
BEGIN
DECLARE #sql NVARCHAR(MAX)
WHILE 1=1
BEGIN
SELECT TOP 1 #sql = N'alter table [TABLE_NAME] drop constraint ['+dc.name+N']'
FROM sys.default_constraints dc
JOIN sys.columns c
ON c.default_object_id = dc.object_id
WHERE dc.parent_object_id = OBJECT_ID('[TABLE_NAME]') AND c.name = N'LOWER_LIMIT'
IF ##ROWCOUNT = 0
BEGIN
PRINT 'DELETED Constraint on column LOWER_LIMIT'
BREAK
END
EXEC (#sql)
END;
ALTER TABLE TABLE_NAME DROP COLUMN LOWER_LIMIT;
PRINT 'DELETED column LOWER_LIMIT'
END
ELSE
PRINT 'Column LOWER_LIMIT does not exist'
GO
In addition to accepted answer, if you're using Entity Migrations for updating database, you should add this line at the beggining of the Up() function in your migration file:
Sql("alter table dbo.CompanyTransactions drop constraint [df__CompanyTr__Creat__0cdae408];");
You can find the constraint name in the error at nuget packet manager console which starts with FK_dbo.
I had the same problem and this was the script that worked for me with a table with a two part name separated by a period ".".
USE [DATABASENAME]
GO
ALTER TABLE [TableNamePart1].[TableNamePart2] DROP CONSTRAINT [DF__ TableNamePart1D__ColumnName__5AEE82B9]
GO
ALTER TABLE [TableNamePart1].[ TableNamePart1] DROP COLUMN [ColumnName]
GO
I needed to replace an INT primary key with a Guid. After a few failed attempts, the EF code below worked for me. If you hyst set the defaultValue... you end up with a single Guid a the key for existing records.
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropUniqueConstraint("PK_Payments", "Payments");
migrationBuilder.DropColumn(
name: "PaymentId",
table: "Payments");
migrationBuilder.AddColumn<Guid>(
name: "PaymentId",
table: "Payments",
type: "uniqueidentifier",
defaultValueSql: "NewId()",
nullable: false);
}
Copy the default constraint name from the error message and type it in the same way as the column you want to delete.
I had the same problem, I could not remove migrations, it would show error that something is already applied, so i changed my DB name in appsettings, removed all migrations, and then added new migration and it worked. Dont understand issue completely, but it worked
I fixed by Adding Dropping constraint inside migration.
migrationBuilder.DropForeignKey(
name: "FK_XX",
table: "TableX").
and below recreates constraint.
migrationBuilder.AddForeignKey(
name: "FK_XX",
table: "TableX",
column: "ColumnX",
onDelete: ReferentialAction.Restrict);
I am new to Postgresql, and I am trying to change the data type of a column from Integer to Varchar(20), but I get strange error:
ERROR: operator does not exist: character varying <> integer :
No operator matches the given name and argument type(s).
You might need to add explicit type casts.********** Error **********
The script I wrote to create the table is:
CREATE TABLE LOGIN(
USERNAME INTEGER NOT NULL CHECK(USERNAME != NULL),
PASSWORD VARCHAR(10) NOT NULL CHECK(PASSWORD <>'' AND USERNAME != NULL)
);
This is the script I used to modify the column from Integer to Varchar:
ALTER TABLE LOGIN ALTER COLUMN USERNAME TYPE varchar(20);
I appreciate any help. Thanks.
Use USING expression. It allows you to define value conversion:
ALTER TABLE LOGIN ALTER COLUMN USERNAME TYPE varchar(20) USING ...expression...;
From PostgreSQL documentation:
The optional USING clause specifies how to compute the new column
value from the old; if omitted, the default conversion is the same as
an assignment cast from old data type to new. A USING clause must be
provided if there is no implicit or assignment cast from old to new
type.
The cause of the error is the useless additional check constraint (<> null) that you have:
operator does not exist: character varying <> integer :
refers to the condition USERNAME != NULL in both of your check constraints.
(the "not equals" operator in SQL is <> and != gets re-written into that)
So you first need to get rid of those check constraints. The default generated name for that check would be login_username_check, so the following will most probably work:
alter table login
drop constraint login_username_check;
The other check is most probably login_check:
alter table login
drop constraint login_check;
Once those check constraints are dropped you can alter the data type:
ALTER TABLE LOGIN
ALTER COLUMN USERNAME set data TYPE varchar(20);
Now you need to re-add the constraint for the password:
alter table login
add constraint check_password check (password <> '');
If for some reason the generated constraint names are different then the ones I assumes, you can find the names using:
select c.conname, c.consrc
from pg_constraint c
join pg_class t on c.conrelid = t.oid
join pg_namespace n on t.relnamespace = n.oid
where t.relname = 'login'
and n.nspname = 'public'; --<< change here for the correct schema name
As jarlh has already commented, defining a column as NOT NULL is enough. There is no need to add another "not null" check. Plus: the check is wrong anyway. You can't compare a value against null using = or <>. To test for a not null value you need to use IS NOT NULL. The correct way to write an explicit check constraint would be
username check (username is not null)
The problem is in USERNAME's CHECK constraint. You may get a way out of it using catalog pg_constraint somehow like that:
SELECT conname, consrc
FROM pg_constraint
WHERE conrelid =
(SELECT oid
FROM pg_class
WHERE relname LIKE 'login');
In a field 'consrc' you may notice that constraints actually look like "(username <> NULL::integer)", and it brings an error when you try to change column type from integer to varchar.
To remove constraints use
ALTER TABLE LOGIN DROP CONSTRAINT login_username_check;
ALTER TABLE LOGIN DROP CONSTRAINT login_check;
where 'login_username_check' and 'login_check' are connames you got from query above (be careful and doublecheck that names).
After that you should try to
ALTER TABLE LOGIN ALTER COLUMN USERNAME TYPE varchar(20);
This should work if your table has no data in it. If it doesn't, add a
ALTER TABLE dev.tests_LOGIN ALTER COLUMN USERNAME TYPE varchar(20) USING USERNAME::VARCHAR;
Than you probably want to restore PASSWORD<>'' check, so you'll have to do one more alter to bring it back. Good luck!
Some PostgreSQL documentation you may find handy:
pg_constraint doc
alter doc
PS: As mentioned above, you don't need to get a constraint (!=NULL) check when you already have NOT NULL in column description. Also, NULL checks are a bit different. Quick illustration:
SELECT (NULL = NULL);
SELECT (NULL != NULL);
SELECT (NULL IS NULL);
SELECT (NULL IS NOT NULL);
I want to change a primary key and all table rows which reference to this value.
# table master
master_id|name
===============
foo|bar
# table detail
detail_id|master_id|name
========================
1234|foo|blu
If I give a script or function
table=master, value-old=foo, value-new=abc
I want to create a SQL snippet that executes updates on all tables which refere to table "master":
update detail set master_id=value-new where master_id=value-new;
.....
With the help of introspection, this should be possible.
I use postgres.
Update
The problem is, that there are many tables which have a foreign-key to the table "master". I want a way to automatically update all tables which have a foreign-key to master table.
The easiest way to deal with primary key changes - by far - is to ALTER your referring foreign key constraints to be ON UPDATE CASCADE.
You are then free to update the primary key values, and the changes will cascade to child tables. It can be a very slow process due to all the random I/O, but it will work.
You do need to watch out not to violate uniqueness constraints on the primary key column during the process.
A fiddlier but faster way is to add a new UNIQUE column for the new PK, populate it, add new columns to all the referring tables that point to the new PK, drop the old FK constraints and columns, then finally drop the old PK.
If you need to change PK you could use DEFFERED CONSTRAINTS:
SET CONSTRAINTS sets the behavior of constraint checking within the current transaction. IMMEDIATE constraints are checked at the end of each statement. DEFERRED constraints are not checked until transaction commit. Each constraint has its own IMMEDIATE or DEFERRED mode.
Data preparation:
CREATE TABLE master(master_id VARCHAR(10) PRIMARY KEY, name VARCHAR(10));
INSERT INTO master(master_id, name) VALUES ('foo', 'bar');
CREATE TABLE detail(detail_id INT PRIMARY KEY, master_id VARCHAR(10)
,name VARCHAR(10)
,CONSTRAINT fk_det_mas FOREIGN KEY (master_id) REFERENCES master(master_id));
INSERT INTO detail(detail_id, master_id, name) VALUES (1234,'foo','blu');
In normal situtation if you try to change master detail you will end up with error:
update detail set master_id='foo2' where master_id='foo';
-- ERROR: insert or update on table "detail" violates foreign key
-- constraint "fk_det_mas"
-- DETAIL: Key (master_id)=(foo2) is not present in table "master"
update master set master_id='foo2' where master_id='foo';
-- ERROR: update or delete on table "master" violates foreign key
-- constraint "fk_det_mas" on table "detail"
-- DETAIL: Key (master_id)=(foo) is still referenced from table "detail".
But if you change FK resolution to deffered, there is no problem:
ALTER TABLE detail DROP CONSTRAINT fk_det_mas ;
ALTER TABLE detail ADD CONSTRAINT fk_det_mas FOREIGN KEY (master_id)
REFERENCES master(master_id) DEFERRABLE;
BEGIN TRANSACTION;
SET CONSTRAINTS ALL DEFERRED;
UPDATE master set master_id='foo2' where master_id = 'foo';
UPDATE detail set master_id='foo2' where master_id = 'foo';
COMMIT;
DBFiddle Demo
Please note that you could do many things inside transaction, but during COMMIT all referential integrity checks have to hold.
EDIT
If you want to automate this process you could use dynamic SQL and metadata tables. Here Proof of Concept for one FK column:
CREATE TABLE master(master_id VARCHAR(10) PRIMARY KEY, name VARCHAR(10));
INSERT INTO master(master_id, name)
VALUES ('foo', 'bar');
CREATE TABLE detail(detail_id INT PRIMARY KEY, master_id VARCHAR(10),
name VARCHAR(10)
,CONSTRAINT fk_det_mas FOREIGN KEY (master_id)
REFERENCES master(master_id)DEFERRABLE ) ;
INSERT INTO detail(detail_id, master_id, name) VALUES (1234,'foo','blu');
CREATE TABLE detail_second(detail_id INT PRIMARY KEY, name VARCHAR(10),
master_id_second_name VARCHAR(10)
,CONSTRAINT fk_det_mas_2 FOREIGN KEY (master_id_second_name)
REFERENCES master(master_id)DEFERRABLE ) ;
INSERT INTO detail_second(detail_id, master_id_second_name, name)
VALUES (1234,'foo','blu');
And code:
BEGIN TRANSACTION;
SET CONSTRAINTS ALL DEFERRED;
DO $$
DECLARE
old_pk TEXT = 'foo';
new_pk TEXT = 'foo2';
table_name TEXT = 'master';
BEGIN
-- update childs
EXECUTE (select
string_agg(FORMAT('UPDATE %s SET %s = ''%s'' WHERE %s =''%s'' ;'
,c.relname,pa.attname, new_pk,pa.attname, old_pk),CHR(13)) AS sql
from pg_constraint pc
join pg_class c on pc.conrelid = c.oid
join pg_attribute pa ON pc.conkey[1] = pa.attnum
and pa.attrelid = pc.conrelid
join pg_attribute pa2 ON pc.confkey[1] = pa2.attnum
and pa2.attrelid = table_name::regclass
where pc.contype = 'f');
-- update parent
EXECUTE ( SELECT FORMAT('UPDATE %s SET %s = ''%s'' WHERE %s =''%s'';'
,c.relname,pa.attname, new_pk,pa.attname, old_pk)
FROM pg_constraint pc
join pg_class c on pc.conrelid = c.oid
join pg_attribute pa ON pc.conkey[1] = pa.attnum
and pa.attrelid = pc.conrelid
WHERE pc.contype IN ('p','u')
AND conrelid = table_name::regclass
);
END
$$;
COMMIT;
DBFiddle Demo 2
EDIT 2:
I tried it, but it does not work. It would be nice, if the script could show the SQL. This is enough. After looking at the generated SQL I can execute it if psql -f
have you tried it? It did not work for me.
Yes, I have tried it. Just check above live demo links.
I prepare the same demo with more debug info:
values before
executed SQL
values after
Please make sure that FKs are defined as DEFFERED.
DBFiddle 2 with debug info
LAST EDIT
Then I wanted to see the sql instead of executing it. I removed "perform" from your fiddle, but then I get an error. See: http://dbfiddle.uk/?rdbms=postgres_10&fiddle=b9431c8608e54b4c42b5dbd145aa1458
If you only want to get SQL code you could create function:
CREATE FUNCTION generate_update_sql(table_name VARCHAR(100), old_pk VARCHAR(100), new_pk VARCHAR(100))
RETURNS TEXT
AS
$$
BEGIN
RETURN
-- update childs
(SELECT
string_agg(FORMAT('UPDATE %s SET %s = ''%s'' WHERE %s =''%s'' ;', c.relname,pa.attname, new_pk,pa.attname, old_pk),CHR(13)) AS sql
FROM pg_constraint pc
JOIN pg_class c on pc.conrelid = c.oid
JOIN pg_attribute pa ON pc.conkey[1] = pa.attnum and pa.attrelid = pc.conrelid
JOIN pg_attribute pa2 ON pc.confkey[1] = pa2.attnum and pa2.attrelid = table_name::regclass
WHERE pc.contype = 'f') || CHR(13) ||
-- update parent
(SELECT FORMAT('UPDATE %s SET %s = ''%s'' WHERE %s =''%s'';', c.relname,pa.attname, new_pk,pa.attname, old_pk)
FROM pg_constraint pc
JOIN pg_class c on pc.conrelid = c.oid
JOIN pg_attribute pa ON pc.conkey[1] = pa.attnum and pa.attrelid = pc.conrelid
WHERE pc.contype IN ('p','u')
AND conrelid = table_name::regclass)
;
END
$$ LANGUAGE plpgsql;
And execution:
SELECT generate_update_sql('master', 'foo', 'foo');
UPDATE detail SET master_id = 'foo' WHERE master_id ='foo' ;
UPDATE detail_second SET master_id_second_name = 'foo'
WHERE master_id_second_name ='foo' ;
UPDATE master SET master_id = 'foo' WHERE master_id ='foo';
DBFiddle Function Demo
Of course there is a place for improvement for example handling identifiers like "table with space in name" and so on.
I found a dirty solution: in psql the command \d master_table show the relevant information. With some text magic, it is possible to extract the needed information:
echo "UPDATE master_table SET id='NEW' WHERE id='OLD';" > tmp/foreign-keys.txt
psql -c '\d master_table' | grep -P 'TABLE.*CONSTRAINT.*FOREIGN KEY' \
>> tmp/foreign-keys.txt
reprec '.*TABLE ("[^"]*") CONSTRAINT[^(]*\(([^)]*)\).*' \
"UPDATE \1 set \2='NEW' WHERE \2='OLD';" \
tmp/foreign-keys.txt
psql -1 -f tmp/foreign-keys.txt
Result:
UPDATE "master_table" SET id='NEW' WHERE id='OLD';
UPDATE "other_table" SET master_id='NEW' WHERE master_id='OLD';
...
But better solutions are welcome.
I dont think you can update the Primary key. One possible work around is that you can remove the primary key constraint from the table column. Then update the column value.
Updating the primary key can lead you to some serious problems. But if you still want to do it.
Please refer this Thread.(kevchadders has given a solution.)
I have three tables a,b and c and need to add a constraint like below for checking the data integrity
The below is wrong but I need help in enforcing the below condition.
ALTER TABLE [a]
ADD CONSTRAINT UOMGROUPIG CHECK UNITOFMEASURID IN (SELECT UnitOfMeasureId FROM b WHERE UOMGroupId=1 )
ALTER TABLE [c]
ADD CONSTRAINT UOMGROUPIG CHECK UNITOFMEASURID IN (SELECT UnitOfMeasureId FROM b WHERE UOMGroupId=2 )
Thanks
A scalar valued function like this works for your example, you can easily modify it and create your second constraint:
CREATE FUNCTION your_schema_name.udf_Check1(
#UNITOFMEASURID INT
)
RETURNS BIT
AS
BEGIN
DECLARE #returnValue BIT = 0
SELECT #returnValue = CASE WHEN COUNT(UnitOfMeasureId) > 0 THEN 1 ELSE 0 END
FROM your_schema_name.b
WHERE UOMGroupId=1
AND #UNITOFMEASURID = UnitOfMeasureId
RETURN #returnValue
END
GO
ALTER TABLE [a]
ADD CONSTRAINT UOMGROUPIG
CHECK (your_schema_name.udf_Check1(UNITOFMEASURID) = 1)
GO
Here is the example: SQL Fiddle
You cannot write query within Check constraint. Instead you can call user defined function.
You can use same function in both constraints by passing #UOMGroupId value along with UNITOFMEASURID.
CREATE FUNCTION CheckFnctn(#UNITOFMEASURID int, #UOMGroupId int)
RETURNS int
AS
BEGIN
if exists(SELECT UnitOfMeasureId FROM b WHERE UOMGroupId=#UOMGroupId
and UnitOfMeasureId = #UNITOFMEASURID)
BEGIN
RETURN 1;
END
RETURN 0; --missed this line
END;
ALTER TABLE [a]
ADD CONSTRAINT UOMGROUPIG CHECK (dbo.CheckFnctn(UNITOFMEASURID, 1)=1);
ALTER TABLE [c]
ADD CONSTRAINT UOMGROUPIG CHECK (dbo.CheckFnctn(UNITOFMEASURID, 2)=1);