I have two SQL Server 2014 tables one has "en-GB" cultured names and descriptions, and a second has translations for other cultures.
The "en-GB" table...
CREATE TABLE [dbo].[HomePages]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Key] NVARCHAR (25) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Description] NVARCHAR (256) NOT NULL,
[Active] BIT CONSTRAINT [DF_HomePages_Active] DEFAULT ((0)) NOT NULL,
CONSTRAINT [PK.dbo.HomePage] PRIMARY KEY CLUSTERED ([Id] ASC)
);
The translation table:
CREATE TABLE [dbo].[HomePageTranslations]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[HomePageId] INT NOT NULL,
[CultureName] NVARCHAR (5) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Description] NVARCHAR (256) NOT NULL,
CONSTRAINT [PK_HomePageTranslations] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_HomePageTranslations_Globalization] FOREIGN KEY ([CultureName]) REFERENCES [dbo].[Globalization] ([CultureName]) ON DELETE CASCADE,
CONSTRAINT [FK_HomePageTranslations_HomePages] FOREIGN KEY ([HomePageId]) REFERENCES [dbo].[HomePages] ([Id]) ON DELETE CASCADE
);
There will always be values in en-GB table, but may or may not be equivalent values in the translation table. The query I am using should return the translated values if they exist or fall back on the en-GB values if they don't. The query is in the stored procedure here:
CREATE PROCEDURE [dbo].[HomePage_GetForKeyAndCulture]
(
@Key NVARCHAR(25),
@CultureName NVARCHAR(5)
)
AS
BEGIN
SELECT [base].[Id],
[base].[Key],
COALESCE(translation.[Name], base.[Name]) [Name],
COALESCE(translation.[Description], base.[Description]) [Description],
[base].[Active]
FROM [dbo].[HomePages] [base]
LEFT JOIN [dbo].[HomePageTranslations] [translation]
ON [translation].[HomePageId] = [base].[Id]
AND [translation].[CultureName] = @CultureName
WHERE [Key] = @Key;
END
As you can see I am using a LEFT JOIN and the COALESCE function to achieve this. I know LEFT JOINS are not overly performant, so is there a more performant way to achieve this?
EDIT: Following advise tables have now had indexes added and look like...
The HOMEPAGE table...
CREATE TABLE [dbo].[HomePages]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[Key] NVARCHAR (25) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Description] NVARCHAR (256) NOT NULL,
[Active] BIT CONSTRAINT [DF_HomePages_Active] DEFAULT ((0)) NOT NULL,
CONSTRAINT [PK.dbo.HomePages] PRIMARY KEY CLUSTERED ([Id] ASC)
);
CREATE UNIQUE NONCLUSTERED INDEX [IX.HomePages_Key]
ON [dbo].[HomePages]([Key] ASC);
And the TRANSLATION table...
CREATE TABLE [dbo].[HomePageTranslations]
(
[Id] INT IDENTITY (1, 1) NOT NULL,
[HomePageId] INT NOT NULL,
[CultureName] NVARCHAR (5) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Description] NVARCHAR (256) NOT NULL,
CONSTRAINT [PK_HomePageTranslations] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_HomePageTranslations_Globalization] FOREIGN KEY ([CultureName]) REFERENCES [dbo].[Globalization] ([CultureName]) ON DELETE CASCADE,
CONSTRAINT [FK_HomePageTranslations_HomePages] FOREIGN KEY ([HomePageId]) REFERENCES [dbo].[HomePages] ([Id]) ON DELETE CASCADE
);
CREATE UNIQUE NONCLUSTERED INDEX [IX_HomePageTranslations_HomePageIdCultureName]
ON [dbo].[HomePageTranslations]([HomePageId] ASC, [CultureName] ASC);
HomePageTranslations.HomePageId
and you will be fine.LEFT JOIN
may be is slower thanINNER
, but with proper indexes in place you will see no difference . In general, "don't fix it till it's broken". There is no silver bullet that works efficiently for all cases.