简体   繁体   中英

T-SQL Where statement - OR

Sorry for the vague title but I really didn't know what title to give to this problem:

I have the following result set:

ID   Field   FieldValue   Culture
1    Color   Groen        nl-NL
2    Taste   Kip          nl-NL
3    Color   Green        en-GB
4    Taste   Chicken      en-GB
5    Color   Green        en
6    Taste   Chicken      en

I would like to mimic the ASP.Net way of resource selection, user Culture (nl-NL)

SELECT Field, FieldValue FROM Tbl WHERE Culture = 'nl-NL'

Or when there are no results for the specific culture, try the parent Culture (nl)

SELECT Field, FieldValue FROM Tbl WHERE Culture = 'nl'

Or when there are no results for the parent culture, try the default Culture (en)

SELECT Field, FieldValue FROM Tbl WHERE Culture = 'en'

How can I combine these SELECT-statements in one T-SQL statement?
I'm using LINQ so a LINQ expression would be even greater.

The OR-statement won't work, because I don't want a mix of cultures.
The ORDER BY-statement won't help, because it returns multiple records per culture.

The output might look like (nl-NL):

Color   Groen
Taste   Kip

or (en-GB / en):

Color   Green
Taste   Chicken

So, here is the code that does exactly what's written in your example. It is expected that you determine specific culture (nl-NL), neutral culture (nl), and fallback culture (en) in the client-side code and feed these values to SQL.

SELECT Field, FieldValue FROM Tbl WHERE Culture = (
    SELECT TOP 1 Culture FROM (
        SELECT 1 as n, Culture FROM Tbl WHERE Culture = 'nl-NL'
        UNION
        SELECT 2, Culture FROM Tbl WHERE Culture = 'nl'
        UNION
        SELECT 3, Culture FROM Tbl WHERE Culture = 'en'
    ) cultures
    ORDER BY n
)

Are you sure you need the whole translation table for a given culture, not a translation of each string? What if you have string A and B in en, but only string A in nl-NL?

Try this:

SELECT Field, FieldValue FROM Tbl WHERE Culture = 'nl-NL' 

union

SELECT Field, FieldValue FROM Tbl WHERE Culture = 'nl' 
and not exists(select * from tbl where culture = 'nl-NL')

union

SELECT Field, FieldValue FROM Tbl WHERE Culture = 'en' 
and not exists(select * from tbl where culture = 'nl-NL')
and not exists(select * from tbl where culture = 'nl')

Linq:

var x = (from a in tbl
        where culture == "nl-NL"
        select a
        )

        .Union

        (from a in tbl
        where culture == "nl"
        && !tbl.Any(c => c.Culture == "nl-NL")
        select a
        )

        .Union
        (from a in tbl
        where culture == "en"
        && !tbl.Any(c => c.Culture == "nl-NL")
        && !tbl.Any(c => c.Culture == "nl")
        select a
        );

Assuming Culture is being passed in in @Culture:

select Field,COALESCE(fc.FieldValue,pc.FieldValue,dc.FieldValue)
from
    Tbl dc
        left join
    Tbl pc
        on
            dc.Field = pc.Field and
            pc.Culture = SUBSTRING(@Culture,1,CHARINDEX('-',@Culture)-1)
        left join
    Tbl fc
        on
            dc.Field = fc.Field and
            fc.Culture = @Culture
where
    dc.Culture = 'en'

will return the entire table (the aliases could be longer - dc = default culture, pc = partial culture, fc = full culture.

Given a target culture return either the complete match, or failing that a match on the parent. (Assumed to be the left 2 characters from the Culture field)

(UPDATED)

-- @TargetCulture represents the culture we are interested in
DECLARE @TargetCulture varchar(5)
SET @TargetCulture = 'nl-NL'

-- Parent represents the Result_Set (as in OP) plus column for the 'parent' culture
;WITH Parent AS
(
    SELECT 
        *, 
        LEFT(Culture, 2) AS parent
    FROM 
        Result_Set
)
SELECT 
    * 
FROM 
    Parent
WHERE
    -- Get either a full matching culture or just a match on the parent
    (@TargetCulture = Culture AND @TargetCulture <> parent)
    OR
    (@TargetCulture <> Culture AND @TargetCulture = parent)

Change the value of the @TargetCulture variable to retrieve culture data for nl , en-GB , and en .

Another method;

SELECT * FROM tbl WHERE tbl.Culture = (
 SELECT COALESCE(
  CASE WHEN EXISTS (SELECT 1 FROM tbl WHERE Culture = @locale) THEN @locale ELSE NULL END,
  CASE WHEN EXISTS (SELECT 1 FROM tbl WHERE Culture = SUBSTRING(@locale, 1, CHARINDEX('-', @locale + '-') - 1)) THEN SUBSTRING(@locale, 1, CHARINDEX('-', @locale + '-') - 1) ELSE NULL END,
  'en'
 )
)


nl-nl -> 'nl-nl'
en -> 'en'
en-xxx -> 'en'
zz-gg -> 'en'
en-gb -> 'en-gb'
ff -> 'en'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM