だからここに私のシナリオがあります:
私は私のプロジェクトのローカリゼーションに取り組んでおり、通常はC#コードでこれを行いますが、SQLを少し強化しようとしているので、SQLでこれをもう少しやりたいと思っています。
環境:SQL Server 2014 Standard、C#(.NET 4.5.1)
注:プログラミング言語自体は無関係である必要があります。完全を期すためだけに含めています。
それで、私は自分が望むものをやや達成しましたが、私が望んでいた程度ではありませんでした。JOIN基本的なもの以外のSQLを実行してからしばらく(少なくとも1年)経ちましたが、これは非常に複雑JOINです。
データベースの関連テーブルの図を次に示します。(他にもたくさんありますが、この部分には必要ありません。)

画像に記述されているすべての関係はデータベースで完全です- PKとFK制約はすべて設定および操作されています。説明されている列はどれもnullできません。すべてのテーブルにはスキーマがありますdbo。
今、私はほとんど私がしたいことをするクエリを持っています:つまり、ANY Id of SupportCategoriesとANY Id of が与えられるとLanguages、それは次のいずれかを返します:
その文字列のためにその言語の右適切な翻訳がある場合(IeはStringKeyId- > StringKeys.Id存在し、中LanguageStringTranslations StringKeyId、LanguageIdとStringTranslationIdの組み合わせが存在し、それはロードStringTranslations.TextそのためStringTranslationId。
場合はLanguageStringTranslations StringKeyId、LanguageIdとStringTranslationIdの組み合わせがなかったしない存在し、それはロードStringKeys.Name値を。Languages.Id与えられていますinteger。
私のクエリは、それが混乱であっても、次のとおりです。
SELECT CASE WHEN T.x IS NOT NULL THEN T.x ELSE (SELECT
    CASE WHEN dbo.StringTranslations.Text IS NULL THEN dbo.StringKeys.Name ELSE dbo.StringTranslations.Text END AS Result
FROM dbo.SupportCategories
    INNER JOIN dbo.StringKeys
        ON dbo.SupportCategories.StringKeyId = dbo.StringKeys.Id
    INNER JOIN dbo.LanguageStringTranslations
        ON dbo.StringKeys.Id = dbo.LanguageStringTranslations.StringKeyId
    INNER JOIN dbo.StringTranslations
        ON dbo.StringTranslations.Id = dbo.LanguageStringTranslations.StringTranslationId
WHERE dbo.LanguageStringTranslations.LanguageId = 38 AND dbo.SupportCategories.Id = 0) END AS Result FROM (SELECT (SELECT
    CASE WHEN dbo.StringTranslations.Text IS NULL THEN dbo.StringKeys.Name ELSE dbo.StringTranslations.Text END AS Result
FROM dbo.SupportCategories
    INNER JOIN dbo.StringKeys
        ON dbo.SupportCategories.StringKeyId = dbo.StringKeys.Id
    INNER JOIN dbo.LanguageStringTranslations
        ON dbo.StringKeys.Id = dbo.LanguageStringTranslations.StringKeyId
    INNER JOIN dbo.StringTranslations
        ON dbo.StringTranslations.Id = dbo.LanguageStringTranslations.StringTranslationId
WHERE dbo.LanguageStringTranslations.LanguageId = 5 AND dbo.SupportCategories.Id = 0) AS x) AS T問題は、それが私を提供することができないということであるALLのSupportCategoriesと、それぞれStringTranslations.Textが存在する場合、または自分StringKeys.Nameが存在していなかった場合。それらのいずれかを提供するのに最適ですが、まったくありません。基本的に、特定のキーの翻訳が言語にない場合、デフォルトでは、StringKeys.NameどちらのStringKeys.DefaultLanguageId翻訳を使用するかを強制します。(理想的には、それもしませんが、代わりにの翻訳をロードStringKeys.DefaultLanguageIdします。クエリの残りの部分で正しい方向を指していれば、それを自分で行うことができます。)
私はこれに多くの時間を費やしましたが、C#で書くだけでよいかどうかを知っています(通常のように)今ではそれが行われています。これをSQLで行いたいのですが、好きな出力を得るのに問題があります。
唯一の注意点は、適用される実際のクエリの数を制限することです。すべての列にはインデックスが付けられており、今のところ気に入っています。実際のストレステストなしでは、さらにインデックスを付けることはできません。
編集:別のメモ、私はデータベースを可能な限り正規化するようにしようとしているので、それを避けることができれば物事を複製したくありません。
サンプルデータ
ソース
dbo.SupportCategories(全体):
Id  StringKeyId
0   0
1   1
2   2dbo.Languages(185レコード、例では2つのみ表示):
Id  Abbreviation    Family  Name    Native
38  en  Indo-European   English English
48  fr  Indo-European   French  français, langue françaisedbo.LanguagesStringTranslations(全体):
StringKeyId LanguageId  StringTranslationId
0   38  0
1   38  1
2   38  2
3   38  3
4   38  4
5   38  5
6   38  6
7   38  7
1   48  8 -- added as exampledbo.StringKeys(全体):
Id  Name    DefaultLanguageId
0   Billing 38
1   API 38
2   Sales   38
3   Open    38
4   Waiting for Customer    38
5   Waiting for Support 38
6   Work in Progress    38
7   Completed   38dbo.StringTranslations(全体):
Id  Text
0   Billing
1   API
2   Sales
3   Open
4   Waiting for Customer
5   Waiting for Support
6   Work in Progress
7   Completed
8   Les APIs -- added as example電流出力
以下の正確なクエリを指定すると、次の出力が行われます。
Result
Billing望ましい出力
理想的には、私は特定を省略できるようにしたいと思いますSupportCategories.Idので(言語38に関係なくかのように、それらのすべてを取得するEnglish使用された、または48 French、またはANY現時点では他の言語):
Id  Result
0   Billing
1   API
2   Sales追加の例
以下のためのローカライズを追加したI考えるFrench(Ieが追加1 48 8にLanguageStringTranslations(:これは一例であるだけで、明らかに私はローカライズされた文字列を追加し、ノート)、出力が変化するであろうStringTranslations)(フランスの例で更新します):
Result
Les APIs追加の望ましい出力
上記の例を考えると、次の出力が必要になります(フランス語の例で更新されます)。
Id  Result
0   Billing
1   Les APIs
2   Sales(はい、技術的にはそれが一貫性の観点から間違っていることを知っていますが、それは状況で望ましいことです。)
編集:
小さな更新、dbo.Languagesテーブルの構造を変更し、Id (int)そこから列を削除し、それを置き換えますAbbreviation(現在はに名前が変更されId、すべての相対的な外部キーと関係が更新されました)。技術的な観点から、これは、テーブルが最初から一意であるISO 639-1コードに制限されているという事実のため、私の意見ではより適切なセットアップです。
Tl; dr
だから:質問、どのように私は返すようにこのクエリを修正することができ、すべてをからSupportCategories、その後のいずれかを返すStringTranslations.TextそのためStringKeys.Id、Languages.Id組み合わせ、またはStringKeys.Nameそれがなかった場合、NOT存在しますか?
私の最初の考えは、現在のクエリを何らかの方法で別のサブクエリとして別の一時型にキャストし、このクエリをさらに別のSELECTステートメントでラップし、必要な2つのフィールド(SupportCategories.IdおよびResult)を選択できるということです。
何も見つからない場合は、通常使用する標準的な方法であるSupportCategoriesC#プロジェクトにすべてをロードし、それに対して上記のクエリをそれぞれに対して手動で実行しますSupportCategories.Id。
ありとあらゆる提案/コメント/批評をありがとう。
また、私はそれが不条理に長いことをおizeびします。曖昧さを望みません。私は頻繁にStackOverflowを使用しており、内容に欠ける質問を見て、ここでその間違いを犯したくありませんでした。
