だからここに私のシナリオがあります:
私は私のプロジェクトのローカリゼーションに取り組んでおり、通常は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 2
dbo.Languages(185レコード、例では2つのみ表示):
Id Abbreviation Family Name Native
38 en Indo-European English English
48 fr Indo-European French français, langue française
dbo.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 example
dbo.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 38
dbo.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
)を選択できるということです。
何も見つからない場合は、通常使用する標準的な方法であるSupportCategories
C#プロジェクトにすべてをロードし、それに対して上記のクエリをそれぞれに対して手動で実行しますSupportCategories.Id
。
ありとあらゆる提案/コメント/批評をありがとう。
また、私はそれが不条理に長いことをおizeびします。曖昧さを望みません。私は頻繁にStackOverflowを使用しており、内容に欠ける質問を見て、ここでその間違いを犯したくありませんでした。