Тож ось мій сценарій:
Я працюю над Локалізацією для мого проекту, і, як правило, я б хотів зробити це в коді C #, однак я хочу зробити це в SQL трохи більше, оскільки я намагаюся трохи підключити свій SQL.
Навколишнє середовище: Стандарт SQL Server 2014, C # (.NET 4.5.1)
Примітка: сама мова програмування має бути неактуальною, я включаю її лише для повноти.
Тож я начебто здійснив те, що хотів, але не в тій мірі, яку хотів. Минув деякий час (щонайменше рік), оскільки я робив будь-які SQL JOIN, крім базових, і це досить складно JOIN.
Ось схема відповідних таблиць бази даних. (Є ще багато, але не потрібно для цієї порції.)

Всі відносини , описані в зображенні є повними в БД - PKі FKобмеження все настройки і експлуатації. Жоден із описаних стовпців не nullвдається. Усі таблиці мають схему dbo.
Тепер у мене є запит, який майже робить те, що я хочу: тобто, з урахуванням БУДЬ-якого ІД SupportCategoriesта будь-якого ІД 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
Проблема полягає в тому, що вона не здатна забезпечити мене все з SupportCategoriesі їх відповідної , StringTranslations.Textякщо вона існує, або їх , StringKeys.Nameякби його не існувало. Це ідеально підходить для надання будь-якого з них, але зовсім не. В основному, слід дотримуватися того, що якщо мова не має перекладу для певного ключа, то за замовчуванням слід використовувати, StringKeys.Nameякий є StringKeys.DefaultLanguageIdперекладом. (В ідеалі, це навіть не зробить, але замість цього завантажте переклад StringKeys.DefaultLanguageId, який я можу зробити сам, якщо вказати в правильному напрямку для решти запиту.)
Я витратив на це багато часу, і я знаю, якби я просто писав це в C # (як це зазвичай роблю), це було б зроблено до цього часу. Я хочу це зробити в SQL, і у мене виникають проблеми з отриманням результатів, які мені подобаються.
Єдине застереження - я хочу обмежити кількість застосованих фактичних запитів. Усі стовпці індексуються і такі, які мені зараз подобаються, і без реального стрес-тестування я не можу їх індексувати далі.
Редагувати: Ще одна примітка: я намагаюся тримати базу даних якомога нормалізованішою, тому не хочу дублювати речі, якщо я можу її уникнути.
Приклад даних
Джерело
dbo.SupportКатегорії (цілий):
Id StringKeyId
0 0
1 1
2 2
dbo.Languages (185 записів, лише два приклади)
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чи будь-яка інша мова на даний момент):
Id Result
0 Billing
1 API
2 Sales
Додатковий приклад
З огляду на те, що я повинен був додати локалізацію для French(тобто додати 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, які є унікальними для початку.
Тл; д-р
Отже: питання про те , як я міг змінити цей запит, який повертає всі від SupportCategoriesі потім повертати або StringTranslations.Textдля того StringKeys.Id, Languages.Idкомбінації, абоStringKeys.Name якщо вона НЕ існує?
Моя початкова думка полягає в тому, що я можу якимось чином передати поточний запит до іншого тимчасового типу як інший підзапит і обернути цей запит у ще одне SELECTтвердження та вибрати два поля, які я хочу ( SupportCategories.Idі Result).
Якщо я нічого не знайду, я просто застосую стандартний метод, який я зазвичай використовую, щоб завантажити все SupportCategoriesв мій проект C #, а потім за допомогою нього запустіть запит, який я маю вище, вручну проти кожного SupportCategories.Id.
Дякую за будь-які пропозиції та коментарі / критику.
Крім того, прошу вибачення за те, що це абсурдно довго, я просто не хочу ніякої двозначності. Я часто буваю на StackOverflow і бачу питання, яким не вистачає суті, не хотів би тут помилитися.
