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)
 Recommendations...

Author  Topic 

phawxby
Starting Member

2 Posts

Posted - 2010-08-09 : 09:17:45
Hi,

As part of an application I'm currently developing I need to support content localisation, initially only a few languages but potentially far more. As a minimum some form of English will be available for every resource but default to en-GB if available, so for example if German isn't available then fall back to en-GB then en. The Locale code in question is a .Net locale code "en-GB", "de", pt-BR", etc.

I have managed to implemented the functionality needed however I'm now looking to optimise it and hopefully remove the cursors.

There are three tables in question however I've simplified them slightly for this example. Consider the Resource and Localisation tables to have a few more columns.

Locale (Id INT PK, LocaleCode VARCHAR(5))
Resource (Id INT PK)
Localisation (ResourceId INT FK, LocaleId INT FK, Content NVARCHAR(MAX))

Info
The GetCultureCascade method simply grabs a locale and performs a few string functions to work out the cascade. So for pt-BR it would return 4 rows of "pt-BR", "pt", "en-GB", "en".
The idea behind the left outer join to load content is to make sure even if no localisations are available on the first pass the Resources to be loaded are still returned so the row is already in the database for any subsequent passes. Any further passes don't need to find out if it's there first before performing and insert or update.
The MissingTrans count aborts the loop when all translations are found

Code

-- Create output table
DECLARE @Output TABLE (
[Id] INT,
[LocaleCode] VARCHAR(5),
[Content] NVARCHAR(MAX),
)

-- Create language cascade table
DECLARE @Cascade TABLE (
Locale varchar(5)
)

-- Load in language cascade data
INSERT
@Cascade
EXEC
GetCultureCascade @Locale

-- Cursor vars
DECLARE @CurrentLocale NVARCHAR(5)
DECLARE @MissingTrans INT
DECLARE @First BIT

DECLARE @Id INT
DECLARE @LocaleCode VARCHAR(5)
DECLARE @Content NVARCHAR(MAX)

DECLARE @Count INT

-- Set @First = 1 to force the first cycle
SET @MissingTrans = 0
SET @First = 1

-- Cursor time
DECLARE LocaleCursor CURSOR FOR
SELECT
[Locale]
FROM
@Cascade

OPEN LocaleCursor

-- Fetch locale into the cursor
FETCH NEXT FROM LocaleCursor INTO @CurrentLocale

-- While fetching is possible and there are (missing translations or first cycle)
WHILE @@FETCH_STATUS = 0 AND (@MissingTrans > 0 OR @First = 1)
BEGIN
-- Load content
DECLARE ContentCursor CURSOR FOR
SELECT
[R].[Id],
[RL].[LocaleCode],
[RL].[Content]
FROM
[Resource] AS [R]
LEFT JOIN
(
SELECT
*
FROM
[Localisation]
LEFT OUTER JOIN
[Locale]
ON
[Locale].[Id] = [Localisation].[LocaleId]
WHERE
[Locale].LocaleCode = @Locale
) AS [RL]
ON
[R].[Id] = [RL].[ResourceId]

-- Open content cursor
OPEN ContentCursor

-- Get first record
FETCH NEXT FROM ContentCursor INTO @Id, @LocaleCode, @Content

-- Start looping
WHILE @@FETCH_STATUS = 0
BEGIN
-- First locale cycle, insert them all
IF(@First = 1)
BEGIN
INSERT INTO @Output
([Id], [LocaleCode], [Content])
VALUES
(@Id, @LocaleCode, @Content)
END
ELSE
BEGIN
-- It is, update it if the content is empty
UPDATE @Output SET [Content] = @Content WHERE [Id] = @Id AND [LocaleCode] IS NULL
END

-- Continue content loop
FETCH NEXT FROM ContentCursor INTO @Id, @LocaleCode, @Content
END

-- Cleanup
CLOSE ContentCursor
DEALLOCATE ContentCursor

-- Check to see if any content is missing. If not then the loop can be broken
SELECT
@MissingTrans = COUNT(*)
FROM
@Output
WHERE
[Content] IS NULL

-- No longer the first
SET @First = 0

-- Next
FETCH NEXT FROM LocaleCursor INTO @CurrentLocale
END

-- Tidyup
CLOSE LocaleCursor
DEALLOCATE LocaleCursor

-- Output
SELECT * FROM @OUTPUT


Cheers
Paul

phawxby
Starting Member

2 Posts

Posted - 2010-08-09 : 10:05:34
Shortly after writing this i realised the Content Cursor can be replaced as with an insert or join into the output table depending on if it is the first iteration of the Locale table. Down to 1 cursor now :-)
Go to Top of Page
   

- Advertisement -