Jadi inilah skenario saya:
Saya sedang mengerjakan Pelokalan untuk proyek saya, dan biasanya saya akan melakukan ini dalam kode C #, namun saya ingin melakukan ini dalam SQL sedikit lebih karena saya mencoba sedikit meningkatkan SQL saya.
Lingkungan: SQL Server 2014 Standard, C # (.NET 4.5.1)
Catatan: bahasa pemrograman itu sendiri seharusnya tidak relevan, saya hanya memasukkannya untuk kelengkapan.
Jadi saya semacam mencapai apa yang saya inginkan, tetapi tidak sejauh yang saya inginkan. Sudah lama (setidaknya satu tahun) sejak saya melakukan SQL JOIN
kecuali yang dasar, dan ini cukup kompleks JOIN
.
Berikut adalah diagram dari tabel-tabel basis data yang relevan. (Ada banyak lagi, tetapi tidak perlu untuk porsi ini.)
Semua hubungan yang dijelaskan dalam gambar lengkap dalam database - PK
dan FK
semua kendala adalah pengaturan dan operasi. Tak satu pun dari kolom yang dijelaskan null
mampu. Semua tabel memiliki skema dbo
.
Sekarang, saya punya pertanyaan yang hampir tidak apa yang saya inginkan: yang, diberikan APAPUN Id dari SupportCategories
dan APAPUN Id dari Languages
, itu akan kembali baik:
Jika ada terjemahan yang tepat-tepat untuk bahasa yang untuk string yang (Ie StringKeyId
-> StringKeys.Id
ada, dan dalam LanguageStringTranslations
StringKeyId
, LanguageId
dan StringTranslationId
kombinasi ada, maka beban StringTranslations.Text
untuk itu StringTranslationId
.
Jika LanguageStringTranslations
StringKeyId
, LanguageId
, dan StringTranslationId
kombinasi itu tidak ada, maka beban StringKeys.Name
nilai. Itu Languages.Id
diberikan integer
.
Permintaan saya, baik berantakan, adalah sebagai berikut:
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
Masalahnya adalah bahwa hal itu tidak mampu memberikan saya semua dari SupportCategories
dan masing-masing StringTranslations.Text
jika ada, OR mereka StringKeys.Name
jika tidak ada. Ini sempurna dalam menyediakan salah satu dari mereka, tetapi tidak sama sekali. Pada dasarnya, itu untuk menegakkan bahwa jika bahasa tidak memiliki terjemahan untuk kunci tertentu, maka default adalah menggunakan StringKeys.Name
yang dari StringKeys.DefaultLanguageId
terjemahan. (Idealnya, itu bahkan tidak akan melakukan itu, tetapi malah memuat terjemahan untuk StringKeys.DefaultLanguageId
, yang bisa saya lakukan sendiri jika menunjuk ke arah yang benar untuk sisa permintaan.)
Saya telah menghabiskan banyak waktu untuk hal ini, dan saya tahu jika saya hanya menulisnya dalam C # (seperti biasanya saya lakukan) itu akan dilakukan sekarang. Saya ingin melakukan ini dalam SQL, dan saya mengalami kesulitan mendapatkan output yang saya suka.
Satu-satunya peringatan, adalah saya ingin membatasi jumlah permintaan aktual yang diterapkan. Semua kolom diindeks dan seperti saya suka untuk saat ini, dan tanpa pengujian stres nyata saya tidak dapat mengindeks lebih lanjut.
Sunting: Catatan lain, saya mencoba untuk menjaga database agar senormalisasi mungkin, jadi saya tidak ingin menduplikasi hal-hal jika saya bisa menghindarinya.
Contoh Data
Sumber
dbo.SupportCategories (Entirety):
Id StringKeyId
0 0
1 1
2 2
dbo.Languages (185 catatan, hanya menampilkan dua untuk contoh):
Id Abbreviation Family Name Native
38 en Indo-European English English
48 fr Indo-European French français, langue française
dbo.LanguagesStringTranslations (Entirety):
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 (Entirety):
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 (Entirety):
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
Output Saat Ini
Dengan kueri persis di bawah, ini menghasilkan:
Result
Billing
Output yang Diinginkan
Idealnya, saya ingin menghilangkan yang spesifik SupportCategories.Id
, dan mendapatkan semuanya, seperti itu (terlepas dari apakah bahasa 38 English
digunakan, atau 48 French
, atau APA SAJA bahasa lain saat ini):
Id Result
0 Billing
1 API
2 Sales
Contoh tambahan
Mengingat saya menambahkan lokalisasi untuk French
(Yaitu menambahkan 1 48 8
ke LanguageStringTranslations
), output akan berubah menjadi (catatan: ini adalah contoh saja, jelas saya akan menambahkan string terlokalisasi ke StringTranslations
) (diperbarui dengan contoh Prancis):
Result
Les APIs
Output yang Diinginkan Tambahan
Diberikan contoh di atas, output berikut akan diinginkan (diperbarui dengan contoh Prancis):
Id Result
0 Billing
1 Les APIs
2 Sales
(Ya, saya tahu secara teknis itu salah dari sudut pandang konsistensi, tetapi itulah yang diinginkan dalam situasi tersebut.)
Edit:
Kecil diperbarui, saya memang mengubah struktur dbo.Languages
tabel, dan menjatuhkan Id (int)
kolom dari itu, dan menggantinya dengan Abbreviation
(yang sekarang diganti namanya menjadi Id
, dan semua kunci asing relatif dan dan hubungan diperbarui). Dari sudut pandang teknis, ini adalah pengaturan yang lebih tepat menurut saya karena tabel tersebut terbatas pada kode ISO 639-1, yang unik untuk memulai.
Tl; dr
Jadi: pertanyaannya, bagaimana bisa saya memodifikasi query ini untuk kembali segala sesuatu dari SupportCategories
dan kemudian kembali baik StringTranslations.Text
untuk itu StringKeys.Id
, Languages.Id
kombinasi, atau yang StringKeys.Name
jika hal itu tidak ada?
Pikiran awal saya, adalah bahwa saya entah bagaimana bisa mengirimkan kueri saat ini ke jenis sementara lain sebagai subquery lain, dan membungkus kueri ini dalam SELECT
pernyataan lain dan memilih dua bidang yang saya inginkan ( SupportCategories.Id
dan Result
).
Jika saya tidak menemukan apa-apa, saya hanya akan melakukan metode standar yang biasanya saya gunakan yaitu untuk memuat semua SupportCategories
ke dalam proyek C # saya, dan kemudian menjalankan query yang saya miliki di atas secara manual terhadap masing-masing SupportCategories.Id
.
Terima kasih atas semua dan semua saran / komentar / kritik.
Juga, saya minta maaf karena terlalu panjang, saya hanya tidak ingin ambiguitas. Saya sering berada di StackOverflow dan melihat pertanyaan yang tidak memiliki substansi, tidak ingin membuat kesalahan itu di sini.