Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2005 Forums
 Transact-SQL (2005)
 Synchronization. How to solve this?

Author  Topic 

shapper
Constraint Violating Yak Guru

450 Posts

Posted - 2007-09-10 : 09:37:34
Hello,

I have 3 tables with their columns:
[Articles] > ArticleId, ArticleText
[Categories] > CategoryId, CategoryText
[CategoriesInArticles] > ArticleId, CategoryId

I created a stored procedure that has the following inputs:
ArticleId, ArticleCategories

ArticleCategories is of type NVARCHAR(Max) and has categories in CSV format: "Category A, Category B, Category C"

I have a function, CSVTable, which I took from SQLTeam.com that creates a table with all the categories.

I need to make a kind of synchronization:
> Update all categories for the given ArticleId. If any Category is no longer associated with any ArticleId (In CategoriesInArticles) then remove it from table Categories.

I created the following code:

INSERT INTO CategoriesInArticles(CategoryId, ArticleId)
SELECT c.CategoryId, @ArticleId
FROM Categories c INNER JOIN CSVTable(@ArticleCategories) ac
ON c.CategoryText = ac.String
LEFT JOIN CategoriesInArticles cia
ON c.CategoryId = cia.CategoryId
WHERE cia.CategoryId IS NULL

INSERT INTO Categories(CategoryId, CategoryText)
SELECT cia.CategoryId, NULL
FROM CategoriesInArticles cia INNER JOIN CSVTable(@ArticleCategories) ac
ON cia.CategoryId = ac.String
LEFT JOIN Categories c
ON cia.CategoryId = c.CategoryId
WHERE c.CategoryId IS NULL

DELETE c
FROM CSVTable(@ArticleCategories) ac INNER JOIN Categories c
ON ac.String = c.CategoryId
LEFT JOIN CategoriesInArticles cia
ON ac.String = cia.CategoryId
WHERE cia.CategoryId IS NULL

The first code block seems to work.
The second and third does not. The problem is that the CSVTable has only the category text and not categories so I get an error in:

ON ac.String = c.CategoryId

I'm not sure if my code is the best way to create the synchronization.

Thanks,
Miguel



jen
Master Smack Fu Yak Hacker

4110 Posts

Posted - 2007-09-10 : 16:02:12
I was actually coding when I realized you have that csvtable source..

fastest is to add the missing column in this csvtable perhaps?



--------------------
keeping it simple...
Go to Top of Page

shapper
Constraint Violating Yak Guru

450 Posts

Posted - 2007-09-11 : 12:20:44
Hi,

Yes, that was what I was trying to do but not able ...

The function CSVTable returns a table with only one column: String

What I need is to create a new table from this one with 2 columns:
StringId and String.

StringId will be taken from table Categories given the value of String.

Then I will use this new table in all my code blocks.

Thanks,
Miguel
Go to Top of Page

jen
Master Smack Fu Yak Hacker

4110 Posts

Posted - 2007-09-11 : 12:38:13
why can't you add another column in csvtable?

--------------------
keeping it simple...
Go to Top of Page

shapper
Constraint Violating Yak Guru

450 Posts

Posted - 2007-09-11 : 21:12:14
Hi,

I tried a new code.
It creates the article but the categories are not created.
Could someone, please, help me out?

Here is my new code:

INSERT INTO CategoriesInArticles(CategoryId, ArticleId)
SELECT c.CategoryId, @ArticleId
FROM Articles c INNER JOIN CSVTable(@ArticleCategories) ac
ON c.CategoryText = ac.String
LEFT JOIN CategoriesInArticles cia
ON c.CategoryId = cia.CategoryId
WHERE cia.CategoryId IS NULL

INSERT INTO Categories(CategoryId, CategoryText)
SELECT cia.CategoryId, NULL
FROM CategoriesInArticles cia
JOIN [Categories] c ON c.CategoryId = cia.CategoryId
INNER JOIN CSVTable(@ArticleCategories) ac ON ac.String = c.CategoryText
WHERE c.CategoryId IS NULL

DELETE c
FROM Categories c
INNER JOIN CSVTable(@ArticleCategories) ac ON ac.String = c.CategoryText
LEFT JOIN CategoriesInArticles cia ON c.CategoryId = cia.CategoryId
WHERE cia.CategoryId IS NULL

Thank You,
Miguel
Go to Top of Page

dinakar
Master Smack Fu Yak Hacker

2507 Posts

Posted - 2007-09-12 : 11:56:38
Please post some sample code from each of the tables and expected output.


Dinakar Nethi
************************
Life is short. Enjoy it.
************************
http://weblogs.sqlteam.com/dinakar/
Go to Top of Page

shapper
Constraint Violating Yak Guru

450 Posts

Posted - 2007-09-13 : 10:06:27
Hi,

I will try to better explain what I am trying to do.

I have 3 tables:

CREATE TABLE Articles (ArticleId INT, ArticleText NVARCHAR(512))

CREATE TABLE Categories (CategoryId INT, CategoryText NVARCHAR(512))

CREATE TABLE CategoriesInCategories (ArticleId INT, CategoryId INT)

Consider the following tables content:

Articles Table

ArticleId ArticleText

1 Game ended 1-1
2 Book Review

Categories Table

CategoryId CategoryText

1 Sports
2 Entertainment

CategoriesInArticles Table

ArticleId CategoryId
1 1
2 2

I need to create the following procedures:

CreateArticle

Create Procedure [CreateArticle]
@ArticleText NVARCHAR(512),
@ArticleCategories NVARCHAR(MAX)
As
Begin
...
End

This procedure should the the following:

1. Create the article in table Articles

2 .Use the function CSVTable that returns a table with all the
categories contained in @ArticleCategories.

For each category check if there is already one with the same
CategoryText in table Categories.

If there is just get the CategoryId and add a new record into
CategoriesInArticles with ArticleId and found CategoryId.

If there isn't any then create the new Category into table
Categories and then add the new record to CategoriesInArticles.


DeleteArticle

Create Procedure [DeleteArticle]
@ArticleId INT
As
Begin
...
End

This procedure should the the following:

1. Delete the article in tables Articles and CategoriesInArticles
given its ArticleId

2 .Delete categories from table Categories that are no longer
associated with any other article (in table
CategoriesInArticles)


UpdateArticle
Create Procedure [UpdateArticle]

@ArticleId INT,
@ArticleText NVARCHAR(512),
@ArticleCategories NVARCHAR(MAX)
As
Begin
...
End

This procedure should the the following:

1. Update the values into Articles Table

2 .Use the function CSVTable that returns a table with all the
categories contained in @ArticleCategories.

I think the easiest way is to delete all the categories from
ArticleId as it is done in DeleteArticle.

Then It creates the new categories as it is done in
CreateArticle.

So basically my procedure SynchronizeCategories was suppose to take care of the categories part.

It is not working and maybe I should integrate the code in the procedures Create, DeleteArticle and UpdateArticle.

Consider I create a new article:

EXEC CreateArticle @ArticleText = "Book launched at sports event" @ArticleCategories = "Entertainment, Business"

The tables would become:

Articles Table

ArticleId ArticleText

1 Game ended 1-1
2 Book Review
3 Book launched at sports event

Categories Table

CategoryId CategoryText
1 Sports
2 Entertainment
3 Business

CategoriesInArticles Table

ArticleId CategoryId
1 1
2 2
3 2
3 3

NOTE: Because there is no category named Business in Categories this must be created.


Then I would updated it:

EXEC UpdateArticle @ArticleId = "3" @ArticleText = "Book launched at sports event" @ArticleCategories = "Sports, Tech"

The tables would become:

Articles Table

ArticleId ArticleText
1 Game ended 1-1
2 Book Review
3 Book launched at sports event

Categories Table

CategoryId CategoryText
1 Sports
2 Entertainment
4 Tech

CategoriesInArticles Table

ArticleId CategoryId
1 1
2 2
3 1
3 4

Note: Since Business category is no longer used by any other article then it is also deleted from Categories.

The new Tech category is then created and associated with the updated article as well as the existing category Sports.

Finally I would delete it:

EXEC DeleteArticle @ArticleId = "3"

The tables would become:

Articles Table

ArticleId ArticleText
1 Game ended 1-1
2 Book Review

Categories Table

CategoryId CategoryText
1 Sports
2 Entertainment

CategoriesInArticles Table

ArticleId CategoryId
1 1
2 2

Note: Since Tech category is no longer used by any other article then it is also deleted from Categories.

The Sports category is not deleted from Categories since it is used by Article with Id=1

Well, I hope I didn't miss anything and I explained it well.

I have been trying my code, either by creating a separate procedure named SynchronizeCategories or inside the Create, Delete and Update procedure.

Until now I was not able to make this work.

Could someone, please, help me out with this?

Thank You Very Much,

Miguel
Go to Top of Page

jen
Master Smack Fu Yak Hacker

4110 Posts

Posted - 2007-09-13 : 12:10:49
1. to make it easier, you need to change the IDs into identity columns
2. I've posted a code for the insert, you should deal with the delete on another procedure, don't put them together
3. call the delete first since it's more of a cleanup then the insert procedure



--I am not the author of this function, just modified it a bit to trim down the spaces before and after the delimiter
CREATE FUNCTION [dbo].[fnSplitText]
(
@RowData varchar(4000),
@SplitOn varchar(5)
)
RETURNS @RtnValue table
(
Row int identity(1,1),
Data varchar(100)
)
AS
BEGIN
Declare @Cnt int
Set @Cnt = 1

While (Charindex(@SplitOn,@RowData)>0)
Begin
Insert Into @RtnValue (data)
Select
Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1)))

Set @RowData = ltrim(rtrim(Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData))))
Set @Cnt = @Cnt + 1
End

Insert Into @RtnValue (data)
Select Data = ltrim(rtrim(@RowData))

Return
END

GO

CREATE TABLE #Articles (ArticleId int identity(1,1), ArticleText NVARCHAR(512))
CREATE TABLE #Categories (CategoryId int identity(1,1), CategoryText NVARCHAR(512))
CREATE TABLE #CategoriesInArticles (ArticleId INT, CategoryId INT)
go
insert into #articles(ArticleText )
select 'Game ended 1-1'
union
select 'Book Review'

insert into #Categories(CategoryText)
select 'Sports'
union
select 'Entertainment'

insert into #CategoriesInArticles(articleid,categoryid)
select 1,1
union
select 2,2
go
declare @articletext nvarchar(600)
,@articlecategories nvarchar(600)

set @articleText = 'Book launched at sports event'
set @ArticleCategories = 'Entertainment,Business'

declare @articleid table(articleid int)
declare @categoryid table(categoryid int)

if not exists(select * from #articles where articletext=@articletext)
begin
insert into #articles(articletext)
output inserted.articleid into @articleid(articleid)
select @articletext

insert into #categories(categorytext)
select data from dbo.fnsplitText(@articlecategories,',') fst
where not exists(select categorytext from #categories
where categorytext=fst.data)

insert into @categoryid(categoryid)
select categoryid from #categories c
join dbo.fnsplittext(@articlecategories,',') fst on c.categorytext=fst.data

insert into #categoriesInArticles(articleid,categoryid)
select a.articleid,c.categoryid
from @articleID a cross join @categoryid c
end

select * from #articles
select * from #categories
select * from #categoriesinArticles



--------------------
keeping it simple...
Go to Top of Page

shapper
Constraint Violating Yak Guru

450 Posts

Posted - 2007-09-13 : 16:14:26
Hi Jen,

I am trying your code. I have one question. What do you mean with:

"3. call the delete first since it's more of a cleanup then the insert procedure"

Do you mean I should call the delete procedure before I run the insert or update code ... got lost on that.

Thank You,
Miguel
Go to Top of Page

jen
Master Smack Fu Yak Hacker

4110 Posts

Posted - 2007-09-13 : 16:20:43
yes
i'm simple minded... what i say is as is

--------------------
keeping it simple...
Go to Top of Page

shapper
Constraint Violating Yak Guru

450 Posts

Posted - 2007-09-14 : 13:54:12
Hi Jen,

Thanks for your code.
I created the Delete and Update procedures and until now it seems to work fine. I am just integrating some code to integrate error detection ... I found this article and I am using it:

http://www.4guysfromrolla.com/webtech/041906-1.shtml

Thanks,
Miguel
Go to Top of Page
   

- Advertisement -