6

I have so tables: enter image description here

and so data at Language table:

enter image description here

and so data at Text table: enter image description here

I have to return text for requested language if it exists and text for default language if it does not exist. Is it possible to do that in one query (no while, please)?

Code:

DECLARE @CommentId  bigint = 1
--DECLARE @LanguageCode  nvarchar(2) = 'en' -- "english text" returns
DECLARE @LanguageCode  nvarchar(2) = 'ua'   -- nothing at this moment

SELECT
     t.CommentId
    ,t.TextId
    ,t.[Text]
    ,t.LanguageId
    ,RequestedLanguageId = @LanguageCode
FROM dbo.common_Text t 
    INNER JOIN dbo.common_LanguageType l 
        ON t.LanguageId = l.LanguageId
WHERE l.Code = @LanguageCode 
    AND t.CommentId = @CommentId

Thank you.

ADDED:

If code requests a text in 'ua' (ukrainian) and this is no any text for this language, so it is going to search text for russian. if found - ok, if don't it will look for a text for english. List of languages can vary.

garik
  • 6,782
  • 10
  • 44
  • 56

1 Answers1

6

Using a recursive CTE, this query builds a table of all languages that point somewhere in their default chain to a language that has the required comment. It shows each language next to its first default that has the required comment. It then filters this table to give you the first available text for the language you selected.

DECLARE @CommentId BIGINT = 1;
DECLARE @LanguageCode NVARCHAR(2) = 'en';

WITH languages AS ( -- base case: language has required comment SELECT lt.LanguageId AS RootLanguageId , lt.LanguageId , lt.Code , lt.DefaultId , 0 AS Level FROM dbo.common_LanguageType lt --WHERE -- lt.LanguageId = lt.DefaultId WHERE EXISTS ( SELECT * FROM dbo.common_Text t WHERE t.CommentId = @CommentId AND t.LanguageId = lt.LanguageId )

UNION ALL

-- recursive case: language is not its own default and
--                 does not have the required comment
SELECT
      l_default.RootLanguageId
    , l.LanguageId
    , l.Code
    , l.DefaultId
    , l_default.Level + 1 AS Level
FROM
                dbo.common_LanguageType l
    INNER JOIN  languages               l_default
        ON l.DefaultId = l_default.LanguageId
WHERE
        l.LanguageId <> l.DefaultId
    AND NOT EXISTS (
        SELECT *
        FROM dbo.common_Text    t
        WHERE 
                t.CommentId = @CommentId
            AND t.LanguageId = l.LanguageId
    )

) SELECT t.Text FROM languages l INNER JOIN dbo.common_Text t ON l.RootLanguageId = t.LanguageId WHERE l.Code = @LanguageCode ;

Try just running

SELECT *
FROM languages;

if you want to get a feel for what the recursive CTE is doing. I've uploaded a script to create the tables, insert some sample data, and run the above code to gist.

Hannah Vernon
  • 70,928
  • 22
  • 177
  • 323
Nick Chammas
  • 14,810
  • 17
  • 76
  • 124