Vì vậy, đây là kịch bản của tôi:
Tôi đang làm việc về Bản địa hóa cho một dự án của tôi và thông thường tôi sẽ thực hiện việc này trong mã C #, tuy nhiên tôi muốn làm điều này trong SQL thêm một chút vì tôi đang cố gắng nâng cấp SQL của mình một chút.
Môi trường: Tiêu chuẩn SQL Server 2014, C # (.NET 4.5.1)
Lưu ý: bản thân ngôn ngữ lập trình không liên quan, tôi chỉ bao gồm nó để hoàn thiện.
Vì vậy, tôi sắp xếp hoàn thành những gì tôi muốn, nhưng không đến mức tôi muốn. Đã được một thời gian (ít nhất là một năm) kể từ khi tôi thực hiện bất kỳ SQL nào JOIN
ngoại trừ những SQL cơ bản và điều này khá phức tạp JOIN
.
Dưới đây là sơ đồ của các bảng có liên quan của cơ sở dữ liệu. (Có nhiều hơn nữa, nhưng không cần thiết cho phần này.)
Tất cả các mối quan hệ được mô tả trong hình ảnh đều hoàn chỉnh trong cơ sở dữ liệu - các ràng buộc PK
và FK
tất cả đều được thiết lập và vận hành. Không có cột nào được mô tả là null
có thể. Tất cả các bảng có lược đồ dbo
.
Bây giờ, tôi có một truy vấn gần như thực hiện những gì tôi muốn: đó là, đưa ra BẤT K Id Id nào SupportCategories
và BẤT K Id Id nào Languages
, nó sẽ trả về:
Nếu có một bản dịch phải thích hợp cho rằng ngôn ngữ cho chuỗi (Ie StringKeyId
-> StringKeys.Id
tồn tại, và trong LanguageStringTranslations
StringKeyId
, LanguageId
và StringTranslationId
kết hợp tồn tại, sau đó nó tải StringTranslations.Text
cho rằng StringTranslationId
.
Nếu LanguageStringTranslations
StringKeyId
, LanguageId
và StringTranslationId
sự kết hợp đã không tồn tại, sau đó nó tải các StringKeys.Name
giá trị. Đây Languages.Id
là một cho trước integer
.
Truy vấn của tôi, có thể là một mớ hỗn độn, như sau:
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
Vấn đề là nó không có khả năng cung cấp cho tôi TẤT CẢ của SupportCategories
và của mình StringTranslations.Text
nếu nó tồn tại, HOẶC họ StringKeys.Name
nếu nó không tồn tại. Nó là hoàn hảo trong việc cung cấp bất kỳ một trong số họ, nhưng không phải là tất cả. Về cơ bản, cần phải thực thi rằng nếu một ngôn ngữ không có bản dịch cho một khóa cụ thể, thì mặc định là sử dụng bản dịch StringKeys.Name
đó là StringKeys.DefaultLanguageId
bản dịch. (Lý tưởng nhất là nó thậm chí sẽ không làm điều đó, mà thay vào đó hãy tải bản dịch cho StringKeys.DefaultLanguageId
cái mà tôi có thể tự làm nếu được chỉ đúng hướng cho phần còn lại của truy vấn.)
Tôi đã dành rất nhiều thời gian cho việc này và tôi biết nếu tôi chỉ viết nó bằng C # (như tôi thường làm) thì bây giờ nó sẽ được thực hiện. Tôi muốn làm điều này trong SQL và tôi gặp khó khăn khi nhận đầu ra mà tôi thích.
Nhắc nhở duy nhất, là tôi muốn giới hạn số lượng truy vấn thực tế được áp dụng. Tất cả các cột được lập chỉ mục và như tôi thích chúng bây giờ và không có kiểm tra căng thẳng thực sự, tôi không thể lập chỉ mục cho chúng thêm.
Chỉnh sửa: Một lưu ý khác, tôi đang cố gắng giữ cơ sở dữ liệu bình thường nhất có thể, vì vậy tôi không muốn sao chép mọi thứ nếu tôi có thể tránh được.
Dữ liệu mẫu
Nguồn
dbo.SupportC loại (Entirety):
Id StringKeyId
0 0
1 1
2 2
dbo. Ngôn ngữ (185 bản ghi, chỉ hiển thị hai ví dụ):
Id Abbreviation Family Name Native
38 en Indo-European English English
48 fr Indo-European French français, langue française
dbo.LacularStringTranslations (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 (Toàn bộ):
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
Sản lượng hiện tại
Đưa ra truy vấn chính xác dưới đây, nó xuất ra:
Result
Billing
Kết quả mong muốn
Lý tưởng nhất, tôi muốn có thể bỏ qua phần cụ thể SupportCategories.Id
và nhận tất cả chúng, như vậy (bất kể ngôn ngữ 38 English
đã được sử dụng hay 48 French
hoặc BẤT K Language ngôn ngữ nào khác vào lúc này):
Id Result
0 Billing
1 API
2 Sales
Ví dụ bổ sung
Nếu tôi đã thêm một bản địa hóa cho French
(Ie add 1 48 8
to LanguageStringTranslations
), đầu ra sẽ thay đổi thành (lưu ý: đây chỉ là ví dụ, rõ ràng tôi sẽ thêm một chuỗi nội địa hóa vào StringTranslations
) (cập nhật với ví dụ tiếng Pháp):
Result
Les APIs
Đầu ra mong muốn bổ sung
Cho ví dụ trên, đầu ra sau đây sẽ được mong muốn (cập nhật với ví dụ bằng tiếng Pháp):
Id Result
0 Billing
1 Les APIs
2 Sales
(Vâng, tôi biết về mặt kỹ thuật đó là sai từ quan điểm nhất quán, nhưng đó là điều sẽ được mong muốn trong tình huống này.)
Chỉnh sửa:
Được cập nhật nhỏ, tôi đã thay đổi cấu trúc của dbo.Languages
bảng và thả Id (int)
cột khỏi nó và thay thế nó bằng Abbreviation
(hiện được đổi tên thành Id
, và tất cả các Khóa ngoài và các mối quan hệ được cập nhật). Theo quan điểm kỹ thuật, đây là một thiết lập phù hợp hơn theo quan điểm của tôi do thực tế là bảng được giới hạn ở các mã ISO 639-1, là duy nhất để bắt đầu.
Tl; dr
Vì vậy: các câu hỏi, làm thế nào có thể tôi sửa đổi truy vấn này để trả lại tất cả mọi thứ từ SupportCategories
và sau đó trở về hoặc là StringTranslations.Text
cho rằng StringKeys.Id
, Languages.Id
sự kết hợp, hoặc những StringKeys.Name
nếu nó đã không tồn tại?
Suy nghĩ ban đầu của tôi, là bằng cách nào đó tôi có thể chuyển truy vấn hiện tại sang một loại tạm thời khác như một truy vấn con khác và bọc truy vấn này trong một SELECT
câu lệnh khác và chọn hai trường tôi muốn ( SupportCategories.Id
và Result
).
Nếu tôi không tìm thấy bất cứ điều gì, tôi sẽ chỉ thực hiện phương pháp tiêu chuẩn mà tôi thường sử dụng đó là tải tất cả SupportCategories
vào dự án C # của mình, và sau đó với nó chạy truy vấn tôi có ở trên theo cách thủ công SupportCategories.Id
.
Cảm ơn cho bất kỳ và tất cả các đề xuất / ý kiến / phê bình.
Ngoài ra, tôi xin lỗi vì nó quá dài một cách vô lý, tôi chỉ không muốn bất kỳ sự mơ hồ nào. Tôi thường xuyên vào StackOverflow và thấy những câu hỏi thiếu chất, không muốn mắc lỗi ở đây.