Updating column from one table based on changes in another table - c#

Forgive me as I'm new to databases. I have a recipe form that the user can enter several ingredients and the recipe name into. With this form I have the following tables: Recipe{recipeID, recipeName} RecipeIngredient{recipeID,ingredientID,measurement} Ingredient{ingredientID, ingredientName}
RecipeIngredients acts as an intermediate table for the one to many relationship (one recipe to many ingredients). I assigned recipeID as a foreign key inside that table to the primary key recipeID in the recipe table. I thought a foreign key would update based on the primary key updating, but if I insert into the Recipe table the RecipeIngredients table does nothing.
The recipe and the ingredients are assigned ID's automatically.I'm trying to link the ID of one recipe to the auto assigned ID's of each ingredient. For example if the user enters in 8 ingredients, a unique ID is assigned to each of those ingredients. I need the RecipeIngredients table to duplicate those ID's and associate them with the auto-assigned Recipe ID.
I've tried several solutions for updating a column based on changes in other tables. I've tried modifying this MySQL update statement and also modifying this SQL server but I can't seem to get either of them to work.
Suggestions?

In general, you will need to get the new recipeID from the first insert, then use that when you insert into the ingredients table.
Do you have access to the newly inserted recipeID from the insert into the recipe table? How are you doing this insert?
Here is an example Stored Procedure which goes into the database to do the insert / update and return the id:
CREATE PROCEDURE [dbo].[spAlertCategoryInsUpd]
#AlertCategoryID int,
#AlertID int,
#CategoryID int,
#ScreenSortOrder int
AS
SET NOCOUNT ON
IF EXISTS(SELECT [AlertCategoryID] FROM [dbo].[AlertCategories] WHERE [AlertCategoryID] = #AlertCategoryID)
BEGIN
UPDATE [dbo].[AlertCategories] SET
[AlertID] = #AlertID,
[CategoryID] = #CategoryID,
[ScreenSortOrder] = #ScreenSortOrder
WHERE
[AlertCategoryID] = #AlertCategoryID
SELECT #AlertCategoryID as AlertCategoryID;
END
ELSE
BEGIN
INSERT INTO [dbo].[AlertCategories] (
[AlertID],
[CategoryID],
[ScreenSortOrder]
)
OUTPUT INSERTED.AlertCategoryID AS AlertCategoryID
VALUES (
#AlertID,
#CategoryID,
#ScreenSortOrder
)
;
END

Related

Audit Table - Can we store the new value on audit table?

I have created the audit table similar to the below code which logs the changes made on the source table. My question is can a audit table contain newly inserted record or it should contain only the updated records/history since the new record is there in source table ?
I am Looking for pros/cons on each approach and best practice.
create table tblOrders
(
OrderID integer Identity(1,1) primary key,
OrderApprovalDateTime datetime,
OrderStatus varchar(20)
)
create table tblOrdersAudit
(
OrderAuditID integer Identity(1,1) primary key,
OrderID integer,
OrderApprovalDateTime datetime,
OrderStatus varchar(20),
UpdatedBy nvarchar(128),
UpdatedOn datetime
)
go
create trigger tblTriggerAuditRecord on tblOrders
after update, insert
as
begin
insert into tblOrdersAudit
(OrderID, OrderApprovalDateTime, OrderStatus, UpdatedBy, UpdatedOn )
select i.OrderID, i.OrderApprovalDateTime, i.OrderStatus, SUSER_SNAME(), getdate()
from tblOrders t
inner join inserted i on t.OrderID=i.OrderID
end
go
It is totally based on your case,
But I would like to have the Audit table to have all records, the new inserted and the updated, so that I can view, check history, do time line calculations,... using just the Audit table as a separate entity without going back to the original table.
Also It might be helpful if I want to roll back to a certain record (it could be the first inserted one)

How to reuse itemID after being deleted

Sorry not good in english, hope you all can understand and please help.
I have unique identity for each item.
In the program, it can only have 200 itemsID
For instance, when the user create the first item, the database will assign itemID 1 to the first item, itemID 2 to second item till itemID 200.
User can delete the items. For instance, user delete from itemID 1 to itemID 20. So when user create a new item, i want to reuse the itemID 1, may i know how can i do about it?
For fresh start, whenever user create new item, i will check database for the max item id then retrieve it and add 1.
mySql_ = "SELECT MAX(ITEM_ID) FROM ITEM";
Object returnValue = ExecuteSql(mySql_);
if (DBNull.Value.Equals(returnValue))
{
ItemId += 1;
}
My table design structure is as follow
CREATE TABLE ITEM (
ID NOT NULL PRIMARY KEY
ITEMID NOT NULL
ITEM_NAME
)
The above will be my table structure. I only allowed to have maximum itemID of 200. For example, user have created 200 items (table will have itemID 1 to 200), So if user want to create more items, they delete from itemID 1 to itemID20. So the next time when user create item, the new item insert to table will be itemID1.
If you are using SQl server and Identity. Identity fields do not reuse old values by default. You can reseed them with DBCC CHECKIDENT (orders, RESEED, 9)
That means you'll have to run the statement based on every DELETE.
It is generally not a good idea to handle IDs yourself. Let SQL Server do this withan identity column. You especially shouldn't reuse IDs after delete if your ID is the orimary key. That will degrade insert and index performance. It is always most efficient to add primary key values at the end of the range.
Especially to query your MAX(ID) is not efficient. If you want to reuse IDs without compromising good DB design, you can create a table that contains your ID pool and link with a foreign key:
CREATE TABLE IDPool (
ID TINYINT NOT NULL PRIMARY KEY
--More columns if you need them
)
This table contains one entry for each reusable ID, so in your case 200 entries with ID 1 to 200
Your item would look somehow like this:
CREATE TABLE Items (
ID INT NOT NULL IDENTITY PRIMARY KEY,
PooledID TINYINT NOT NULL FOREIGN KEY REFERENCES IDPool(ID)
--Your other columns
)
You can insert new items like this:
INSERT INTO Items (PooledID)
VALUES ((SELECT MIN(ID) FROM IDPool p WHERE NOT EXISTS (
SELECT * FROM Items i WHERE p.PooledID = i.ID
)))
I don't think that your approach is good. You should use identity field which is always unique and don't use old id's anyway. But if you really want to use your approach try to create one more attribute in database. Let's say Hidden field.
When user delete record in application you just update this row and set it as Hidden (Hidden=1).
When user create new record you again update this record and set it to visible (Hidden=0).
The you can build application based on this filed and you can show/hide/work with records in base of Hidden attribute.

How to handle duplicates in SQL Server

I have a table in SQL Server called Test_Table with two columns: ID and Name
The table looks something like this:
ID NAME
--------
1 John
2 Jane
Now I have a stored procedure which inserts records into this.
INSERT INTO Test_Table
VALUES (#Id,#Name)
And I'm passing this values from my c# code. Now I want to modify this so that the table does not have duplicates. Where should I check this, In the code or the DB? I'm very weak in DB side stuff. So how can I handle duplicates before inserting values in my table
The "right" way to do that is in DB because:
Don't need to read all DB
Need to pass all data to C# which increase the IO
Concurrency - if you have more than 1 C# application you will need to sync them vs in DB it would be simpler
You can define the column as unique or key, which will prevent duplicate values ,DB will take care of it
If you use MSSQL use UNIQUE Constraints
Read this good answer about avoid duplicates
You should do this check in the database. Always, if you want it to be true of the data.
I'm not sure what you consider a duplicate. Normally, an id column would be an identity column that is automatically incremented for each value. This would prevent duplicates. You would define it as:
create table test_table (
id int not null identity(1, 1),
. . .
Then, you would insert into it using:
insert into test_table(name)
values (#Name);
The id would be assigned automatically.
If you want no duplicates just for name, then create a unique index or unique constraint (really the same thing). You can do this in the table definition just by adding unique to the column:
create table test_table (
id int not null identity(1, 1),
name varchar(255) unique
. . .
Or by creating a unique index after you have created the table:
create index test_table_name on test_table(name)
(Or by explicitly creating a constraint, which is another method.)
In either case ,you will have to access to database to check wheteher values exist already.
IF NOT EXISTS (SELECT * FROM Test_Table WHERE ID= #ID AND Name=#Name)
BEGIN
INSERT INTO Test_Table
VALUES (#Id,#Name)
END
If it is possible to make ID column as unique you can avoid checking as insertion would.t be allowed for repeating ID values , in that case you will have to handle error.
See this thread how to handle violation of Unique key constraint.
If you don't want repeating IDs you'll have to set the ID as the Primary Key, which is pretty much obligatory.
If you don't want the Name to repeat, you could populate a list with the Names the table contains, and then you would only insert whatever name is not in that List.
Here is an example, instead of using a list I used a dictionary:
Dictionary<int, string> Names = new Dictionary<int, string> ();
using (SqlCommand command = new SqlCommand ("SELECT * FROM TestTable", con))
using (SqlDataReader reader = command.ExecuteReader ()) {
while (reader.Read ()) {
Names.Add (reader["ID"], reader["NAME"]);
}
}
if (!Names.ContainsValue ("ValueYouWantToInsert")) {
//do stuff
}
You should check it in DB, Also you can make ID as Primary Key
Which is mostly used, because people can have duplicate name.
You can modify your Id with the Unique key constraint or you can also make it Primary key.
Try like this:
alter table Test_Table add primary key (ID)
and
alter table Test_Table add unique key (Name)
IF NOT EXISTS (SELECT * FROM Test_Table WHERE ID= #ID AND Name=#Name)
BEGIN
INSERT INTO Test_Table
VALUES (#Id,#Name)
END
ELSE
BEGIN
UPDATE Test_Table
SET ID= #ID,NAME = #Name
WHERE ID= #ID AND Name=#Name
END

SQL: Associate a single type with multiple records of various other types

Designing a database with many tables and want to add a general Note table. I want a Note object to be able to attach to several other tables. So one Note can be associated with a particular Contact, maybe a Job, and also a few different Equipment objects. I'd like to be able to filter Note objects by the particular objects they are associated with.
Well, here's one way:
CREATE TABLE NoteTables
(
TableID INT NOT NULL Identity(1,1),
TableName SysName NOT NULL,
CONSTRAINT PK_NoteTables PRIMARY KEY CLUSTERED(TableID)
)
GO
CREATE TABLE TableNotes
(
TableID INT NOT NULL,
RowID INT NOT NULL,
NoteID INT NOT NULL,
CONSTRAINT PK_NoteAttachments PRIMARY KEY CLUSTERED(TableID, RowID, NoteID)
)
GO
CREATE TABLE Notes
(
NoteID INT NOT NULL Identity(1,1),
Note NVARCHAR(MAX),
CONSTRAINT PK_Notes PRIMARY KEY CLUSTERED(NoteID)
)
Note that I am assuming SQL Server and the use of IDENTITY columns here (if Oracle, you can use Sequences instead).
The Notes table contains all of the notes and gives them an ID to use as both a referemce and a primary key.
The NoteTables just list all of the tables that can have note attached to their rows.
TableNotes links the notes to the tables and rows that they are attached to. Note that this design assumes that all of these tables have INT ID columns that can be used for unique referencing.
It would take you two tables. Structure is as easy as the following.
Note table:
NotePK | tableFK | note
And a table that lists all your tables.
Either you create one (then you have full control but need to maintain it) or you take the
sys.tables t
You read it out by SELECT * FROM sys.tables t
the column object_id would be your tableFK in the first table
You can store as many comments as you like. If you want to get the note simply query the note table and filter for your tableFK.

Regarding some Update Stored procedure

I have two tables as follows:-
Table1:
-------------------------------------
PageID|Content|TitleID(FK)|LanguageID
-------------------------------------
1 |abc |101 |1
2 |xyz |102 |1
--------------------------------------
Table2:
-------------------------
TitleID|Title |LanguageID
-------------------------
101 |Title1|1
102 |Title2|1
------------------------
I don't want to add duplicates in my Table1 (content table). Like.. there can be no two pages with the same title. What check do I need to add in my Insert/Update Stored Procedure? How do I make sure duplicates are never added.
I have tried as follows:-
CREATE PROC InsertUpdatePageContent
(
#PageID int,
#Content nvarchar(2000),
#TitleID int
)
AS
BEGIN
IF(#PageID=-1)
BEGIN
IF(NOT EXISTS(SELECT TitleID FROM Table1 WHERE LANGUAGEID = #LANGUAGEID))
BEGIN
INSERT INTO Table1(Content,TitleID)
VALUES(#Content,#TitleID)
END
END
ELSE
BEGIN
IF(NOT EXISTS(SELECT TitleID FROM Table1 WHERE LANGUAGEID = #LANGUAGEID))
BEGIN
UPDATE Table1
SET Content = #Content, TitleID = #TitleID
WHERE PAGEID = #PAGEID
END
END
END
Now what is happening is that it is inserting new records alright and won't allow duplicates to be added but when I update its giving me problem.
On my aspx Page I have a drop down list control that is bound to DataSource that returns Table 2 (title table) and I have a text box in which user types Page's content to be stored.
When I update, like lets say I have a row in my Table 1 as shown above with PageID=1.
Now when I am updating this row, like I didn't change the Title from the drop down and only changed Content in the text box, its not updating the record ..and when Stored procedure's Update Query does not execute it displays a Label that says "Page with this title exists already."
So whenever I am updating an existing record that label is displayed on screen.How do I change that IF condition in my Update stored procedure??
EDIT:
#gbn: will that IF condition work in case of update? I mean lets say I am updating the Page with TitleID=1, I changed its content, then when I update, it's gonna execute that IF condition and it still won't update coz TitleID=1 already exits!It will only update if TitleID=1 is not there in Table1. Isn't it? Guess I am getting confused. Please answer. Thanks.
Applying a UNIQUE key constraint on TitleID in Table 1 would ensure that no duplicate values for TitleID get saved into the table.
And as far as your stored procedure's code is concerned, gbn's reply highlights the conditional check to be corrected to make it work.
For Update, you cna put this condition to avoid same titles for multiple pages..
IF NOT EXISTS (SELECT 1 from Table1 where TitleId = #TitleID and PageID <> #PageID) -- This makes sure that there is no 'other page' with same title (updated from UI)
{
UPDATE Table1
SET Content = #Content, TitleID = #TitleID
WHERE PAGEID = #PAGEID
}
This will always return false
IF(NOT EXISTS(SELECT TitleID FROM Table1 WHERE LANGUAGEID=LANGUAGEID))
You are comparing a column with itself, it matches = EXISTS
It should be something like
CREATE PROC InsertUpdatePageContent (
#PageID int,
#Content nvarchar(2000),
#TitleID int
)
AS
IF(#PageID=-1)
BEGIN
IF NOT EXISTS (SELECT TitleID FROM Table1 WHERE TitleID=#TitleID)
INSERT INTO Table1(Content,TitleID) VALUES(#Content,#TitleID)
END
ELSE
UPDATE Table1 SET Content= #Content, TitleID=#TitleID WHERE PAGEID=#PAGEID
GO
To protect your data, you should have unique index on TitleID in Table1.
I am not sure I completely understand, but I'll take a shot at it for you. I will assume you can't change your data structure.
First I would put a unique constraint on the Title column in the Table2. Then I would put a unique constraint on the TitleId (FK) in the Table1. This will ensure that you don't have two entries in Table1 with the same title.
Then in the stored procedure I would do the comparison against the parameters being brought in and what exists in the database so that either update or insert is being validated against what's being passed in.
I normally use stored procedures as an API between the relational data model and the object model for some software. I rarely expose database identity columns to stored procedure signatures for applications. Database identity columns get treated differently than unique identifiers that software might use to identify entities. It's hard to help much more without additional information about the rest of the application and other stored procedures that need to work together for your solution.

Categories

Resources