How can I define a foreign key constraint like this in ORACLE:
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY ("StoreTable", STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
/
I want to combine all Enum values of several tables in one table.
In order to create a foreign key I need also to check the type of the enum since the value alone is not unique.
I need it like this so I can define the Store_Type as enum (C#) in my program but at the same time I want to make sure the database values are all valid.
For example:
TEST_STORE table:
| ID | ... | STORE_TYPE
|-----------|------------|------------
| 324234 | | 0
| 324235 | | 0
| 324236 | | 1
TEST_ENUMERATIONS table:
| ID | TABLE | VALUE | NAME
|-----------|--------------|------------|-------------
| 567234 | StoreTable | 0 | NormalStore
| 567235 | StoreTable | 1 | SpecialStore
| 567236 | AnotherTable | 0 | AnotherType
Try creating a virtual column on TEST_STORES whose value is always 'StoreTable', and use the virtual column as the first column in the foreign key.
ALTER TABLE TEST_STORES ADD (ENUM_TABLE AS 'StoreTable');
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY (ENUM_TABLE, STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
Seems that you need:
ALTER TABLE TEST_STORES ADD CONSTRAINT FK_STORE_TYPE
FOREIGN KEY (NAME, STORE_TYPE) REFERENCES TEST_ENUMERATIONS (TABLE, VALUE)
/
You will need a unique key on test_enumerations(table,value) as well.
Related
I have the following scenario:
I have a Contact with properties FirstName and LastName. A Contact can have multiple PhoneNumbers and as many EmailAddresses. I have identified these as 3 entities with common relationships. Please see the table definitions below:
create table Contact
(
ID int primary key not null identity(1,1),
FirstName nvarchar(40),
LastName nvarchar(40)
);
go
create table ContactNumber
(
ID int primary key not null identity(1,1),
PhoneNumber nvarchar(40)
);
go
create table EmailAddress
(
ID int primary key not null identity(1,1),
EmailAddress nvarchar(40)
);
go
create table UserContact
(
ID int primary key not null identity(1,1),
ContactID int foreign key references Contact(ID),
ContactNumberID int foreign key references ContactNumber(ID),
EmailID int foreign key references EmailAddress(ID)
);
go
Now I need to display these users in a Web Application of my choice. I chose C# MVC with a Razor Engine for the View. I'm battling to model this view in a table. The table needs Action Links to edit, delete, create a new contact and view the details of the contact. I want the result set to show as below:
FirstName | LastName | ContactNumber | EmailAddress
-------------------------------------------------------
James | Smith | 082 111 5454 | james#domain1.com | edit | details | delete
| james#domain2.com
| james#domain3.com
--------------------------------------------------------
Luther | Arnolds | 082 111 5455 | luther#domain1.com | edit | details | delete
| 082 111 5456 |
--------------------------------------------------------
Sarah | Jones | 082 111 5510 | sarah#domain.com | edit | details | delete
---------------------------------------------------------
| | |
However I'm just not finding the write way to translate the ContactNumberID and EmailID columns from UserContact to map from their corresponding bridging tables. The issue that I am facing right now is that it is duplicating the records in UserContact thus making the table contain a lot of redundant data. For example the record for James Smith would be repeated 3 times. How can I achieve this in ASP.Net MVC without any duplication of entries?
I would do something like this. Notice that I changed up the column names a little bit. It is a pet peeve of mine to have a column named ID. It is a ContactID (or whatever) regardless of which table it is in. I also really dislike column names changing for the same piece of data in related tables.
create table Contact
(
ContactID int primary key not null identity(1,1),
FirstName nvarchar(40) not null,
LastName nvarchar(40) not null
);
go
create table ContactNumber
(
ContactNumberID int primary key not null identity(1,1),
PhoneNumber nvarchar(40) not null,
ContactID int not null,
constraint FK_ContactNumber_Contact_ContactID Foreign Key (ContactID) references Contact(ContactID)
);
go
create table EmailAddress
(
EmailAddressID int primary key not null identity(1,1),
EmailAddress nvarchar(40) not null,
ContactID int not null,
constraint FK_EmailAddress_Contact_ContactID Foreign Key (ContactID) references Contact(ContactID)
);
go
I have little Confusion that when we delete Category is it necessary to delete Subcategory related to that if so please help by writing Sql query?Similarly if delete subcategory then deleting Category will also should be deleted as well?
+-------+------------+
| CatID | CatName |
+-------+------------+
| 1 | Seeds |
| 2 | Pesticides |
| 3 | Fertilizer |
+-------+------------+
+----------+---------------+-----------+
| SubCatID | SubCatName | CatID |
+----------+---------------+-----------+
| 1 | Red Seed | 1 |
| 2 | Red Seed | 1 |
| 3 | Red Seed | 1 |
| 4 | Red Seed | 1 |
| 5 | National Worm | 2 |
+----------+---------------+-----------+
You need ON DELETE CASCADE by altering current schema :
ALTER TABLE SubCategory
ADD CONSTRAINT fk_SubCat_CatID FOREIGN KEY (CatID) REFERENCES category(CatID )
ON DELETE CASCADE;
By this when you delete category from category table, the reference data would auto delete. Just make sure drop your current constraint before create new one with ON DELETE CASCADE.
Given you have a Foreign Key defined on this relation, then yes, you have to delete (because childs cannot be orphans) or set null (if you column CatId allows null values) on the CatID column on the Subcategories table because the relational databases uses the referential integrity. You can define the CASCADE option to do it for you automatically.
ALTER TABLE SubCategory
ADD CONSTRAINT FK_SubCategory_Category
FOREIGN KEY (CatId)
REFERENCES Category (CatId)
ON DELETE CASCADE
Check this article for more details.
If you have a FK and want more control what you are deleting, you must provide two sql statements to make it, for sample.
delete from subcategory where catId = 1
delete from category where catId = 1
I have a table storing Device details. For simplicity, the columns are:
Id (Primary Key)
Name (varchar)
StatusId (Foreign Key to Status table).
The Status table has two columns:
Id (Primary Key)
State (varchar)
and two rows:
[Id | State]
1 | Active
2 | Inactive
I would like to allow multiple devices in the Devices table with the same Name, but only one of them can have status Active at any time.
That is to say, this should be allowed in the Devices table:
[Id | Name | StatusId]
10 | Mobile001 | 1
11 | Mobile001 | 2
12 | Mobile001 | 2
20 | Tablet001 | 1
21 | Tablet002 | 2
22 | Tablet002 | 1
23 | Tablet003 | 2
But this should not be allowed:
[Id | Name | StatusId]
10 | Mobile001 | 1 <-- wrong
11 | Mobile001 | 1 <-- wrong
12 | Mobile001 | 2
20 | Tablet001 | 1
21 | Tablet002 | 1 <-- wrong
22 | Tablet002 | 1 <-- wrong
23 | Tablet003 | 2
Is there a way how to create a constraint in T-SQL to reject inserts and updates that violate this rule? And is there a way how to do it in EF code first using EntityTypeConfigurations and Fluent API, possibly via IndexAnnotation or IndexAttributes?
Thanks.
One method, as #ZoharPeled just commented is using a filtered unique index.
As you are only allowed one Active Device of a specific name, this can be implemented as below:
USE Sandbox;
GO
--Create sample table
CREATE TABLE Device (ID int IDENTITY(1,1),
[name] varchar(10),
[StatusID] int);
--Unique Filtered Index
CREATE UNIQUE INDEX ActiveDevice ON Device ([name], [StatusID]) WHERE StatusID = 1;
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 0); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile2', 1); --Works
GO
INSERT INTO Device ([name], StatusID)
VALUES ('Mobile1', 1); --Fails
GO
UPDATE Device
SET StatusID = 1
WHERE ID = 2; --Also fails
GO
SELECT *
FROM Device;
GO
DROP TABLE Device;
Any questions, please do ask.
In EF CF You could achieve it by setting an unique index like described in this answer.
modelBuilder.Entity<Device>()
.HasIndex(d => new { d.Name, d.StatusId })
.IsUnique();
I have one central and two client database that have the same structure (identity id). The application allows users to merge data of selected tables from central db with one client db at a time.
For example:
[db_central].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 1 | A |
| 2 | B |
| 3 | C |
+---------------+
[db_client_1].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 3 | D |
+---------------+
[db_client_2].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 3 | E |
+---------------+
Expected result after merging (twice):
[db_central].[table]:
+-------+-------+
| id | name |
+-------+-------+
| 1 | A |
| 2 | B |
| 3 | C |
| 4 | D |
| 5 | E |
+---------------+
Currently, I'm only able to load tables from database.
When user clicks "Manual Sync" button, the app will compare and merge data of selected tables from left to right database or vice versa.
If table doesn't exist, it will create the new one. If table does exist, it will compare and merge data but I don't know what is the best solution to accomplish this task.
Any suggestion would be appreciated.
This seems like a simple sql query (if the databases are on the same server, or if you have a linked server between them) using except...
insert into db_central // Target table
select name from db_client_1 // Source table
except
select name from db_central // Target table
If you have to do it in Linq, then it's very similar:
// Get the list of names to add
var newNames = dbContext.db_client_1.Select(e => e.name).Except(dbContext.db_central.Select(e => e.name));
// Convert the names to a list of entity objects and add them.
dbContext.db_central.Add(newNames.Select(e => new db_central { name = e.name });
dbContext.SaveChanges();
This is assuming you don't want duplicates in db_central
Ideally you should have two columns at table in Central Database
Primary key (with identity enabled)
ChildKey (Primary Key of Child databases)
Primary key column in central database will take care of ordering, and chiild column will give you primary key in respective database
I have one table that stores 3k records,
I'm new with Entity Framework and ORMs but i can understand that something going wrong.
When i run this linq query :
repo.GetQuery<Article>().Where(foo=>foo.Expires_date>=date
&& foo.Istoparticle==true
&& foo.Isfrontpage==false)
.OrderByDescending(foo=>foo.Date)
.Take(4);
I get this query on mysql side :
SELECT
`Project1`.`Id`,
`Project1`.`User_id`,
`Project1`.`Category_id`,
`Project1`.`Title`,
`Project1`.`Value`,
`Project1`.`Keywords`,
`Project1`.`Description`,
`Project1`.`Images`,
`Project1`.`Votes`,
`Project1`.`Views`,
`Project1`.`Isvisible`,
`Project1`.`Isfrontpage`,
`Project1`.`Istoparticle`,
`Project1`.`Date`,
`Project1`.`Expires_date`,
`Project1`.`Votes_sum`
FROM (SELECT
`Extent1`.`Id`,
`Extent1`.`User_id`,
`Extent1`.`Category_id`,
`Extent1`.`Title`,
`Extent1`.`Value`,
`Extent1`.`Keywords`,
`Extent1`.`Description`,
`Extent1`.`Images`,
`Extent1`.`Votes`,
`Extent1`.`Votes_sum`,
`Extent1`.`Views`,
`Extent1`.`Isvisible`,
`Extent1`.`Isfrontpage`,
`Extent1`.`Istoparticle`,
`Extent1`.`Expires_date`,
`Extent1`.`Date`
FROM `tcms_articles` AS `Extent1`
WHERE `Extent1`.`Expires_date` >= '2012-06-24 13:41:47.816') AS `Project1`
ORDER BY
`Project1`.`Date` DESC LIMIT 4
It takes about 3.50 sec to exequte this query.
Explain of this query :
+----+-------------+------------+-------+---------------+--------------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+--------------+---------+------+------+----------------+
| 1 | PRIMARY | | ALL | NULL | NULL | NULL | NULL | 4054 | Using filesort |
| 2 | DERIVED | Extent1 | range | expires_date | expires_date | 8 | NULL | 4053 | Using where |
+----+-------------+------------+-------+---------------+--------------+---------+------+------+----------------+
When i query :
SELECT *
FROM tcms_articles
WHERE expires_date >= '2012-06-24 13:41:47.816'
ORDER BY date DESC
limit 4
I get 0.01 sec...
Running explain again i get :
+----+-------------+---------------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | tcms_articles | index | expires_date | date | 8 | NULL | 11 | Using where |
+----+-------------+---------------+-------+---------------+------+---------+------+------+-------------+
I don't understand why this is happening.
Entity Framework 4.3
MySQL Connector Net 6.5.4.0
EDIT :
The tcms_articles :
CREATE TABLE `tcms_articles` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`User_id` int(10) unsigned DEFAULT NULL,
`Category_id` int(10) unsigned DEFAULT NULL,
`Title` varchar(255) DEFAULT NULL,
`Value` longtext,
`Keywords` varchar(255) NOT NULL DEFAULT '',
`Description` varchar(255) NOT NULL DEFAULT '',
`Images` longtext NOT NULL,
`Votes` int(10) unsigned NOT NULL DEFAULT '1',
`Votes_sum` int(10) unsigned NOT NULL DEFAULT '5',
`Views` int(10) unsigned NOT NULL DEFAULT '0',
`Isvisible` tinyint(1) unsigned NOT NULL DEFAULT '1',
`Isfrontpage` tinyint(1) unsigned NOT NULL DEFAULT '0',
`Istoparticle` tinyint(1) unsigned NOT NULL DEFAULT '1',
`Expires_date` datetime NOT NULL DEFAULT '2099-12-31 00:00:00',
`Date` datetime NOT NULL,
PRIMARY KEY (`Id`),
KEY `article_users` (`User_id`) USING BTREE,
KEY `article_section` (`Category_id`) USING BTREE,
KEY `Isvisible_index2` (`Isvisible`) USING BTREE,
KEY `Istoparticle_index2` (`Istoparticle`) USING BTREE,
KEY `Expires_date_index2` (`Expires_date`) USING BTREE,
KEY `isfrontpage2` (`Isfrontpage`) USING BTREE,
KEY `Date_index2` (`Date`) USING BTREE,
CONSTRAINT `tcms_articles_ibfk_1` FOREIGN KEY (`Category_id`) REFERENCES `tcms_categories` (`Id`)
ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `tcms_articles_ibfk_2` FOREIGN KEY (`User_id`) REFERENCES `tcms_users` (`Id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=80 DEFAULT CHARSET=utf8;
So why Linq produces this query and how/can i fix this?
repo.GetQuery<Article>().Where(foo=>foo.Expires_date>=date -- Note 1
&& foo.Istoparticle==true
&& foo.Isfrontpage==false)
.OrderByDescending(foo=>foo.Date) -- Note 2
.Take(4);
Use foo.Expires_date in both places.