Quindi, ecco il mio scenario:
Sto lavorando su Localization per un mio progetto e in genere vorrei fare questo nel codice C #, tuttavia voglio farlo un po 'di più in SQL poiché sto cercando di potenziare un po' il mio SQL.
Ambiente: SQL Server 2014 Standard, C # (.NET 4.5.1)
Nota: il linguaggio di programmazione stesso dovrebbe essere irrilevante, lo sto solo includendo per completezza.
Quindi ho realizzato quello che volevo, ma non nella misura in cui volevo. È passato un po 'di tempo (almeno un anno) da quando ho fatto qualsiasi SQL JOINtranne quelli di base, e questo è piuttosto complesso JOIN.
Ecco uno schema delle tabelle pertinenti del database. (Ce ne sono molti altri, ma non necessari per questa porzione.)

Tutte le relazioni descritte nell'immagine sono complete nel database: i vincoli PKe FKsono tutti impostati e funzionanti. Nessuna delle colonne descritte è in nullgrado. Tutte le tabelle hanno lo schema dbo.
Ora, ho una query che fa quasi quello che voglio: cioè, dato QUALSIASI ID di SupportCategoriese QUALSIASI ID di Languages, restituirà:
Se c'è una traduzione destro adeguata per tale lingua per quella stringa (Ie StringKeyId-> StringKeys.Idesiste, e in LanguageStringTranslations StringKeyId, LanguageIde StringTranslationIdesiste combinazione, allora carichi StringTranslations.Textper quella StringTranslationId.
Se la LanguageStringTranslations StringKeyId, LanguageIde StringTranslationIdcombinazione ha NON esiste, allora carica il StringKeys.Namevalore. Il Languages.Idè un dato integer.
La mia domanda, sia essa un casino, è la seguente:
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
Il problema è che non è in grado di fornire me ALL del SupportCategoriese la loro rispettiva StringTranslations.Textse esiste, o il loro StringKeys.Namese non esistesse. È perfetto per fornire uno di loro, ma per niente. Fondamentalmente, è per imporre che se una lingua non ha una traduzione per una chiave specifica, l'impostazione predefinita è quella StringKeys.Nameche è di StringKeys.DefaultLanguageIdtraduzione. (Idealmente, non lo farebbe nemmeno, ma caricherà invece la traduzione StringKeys.DefaultLanguageId, cosa che posso fare da solo se puntato nella direzione giusta per il resto della query.)
Ho trascorso MOLTO tempo su questo, e so che se dovessi semplicemente scriverlo in C # (come faccio di solito) ormai sarebbe stato fatto. Voglio farlo in SQL e ho problemi a ottenere l'output che mi piace.
L'unica avvertenza è che voglio limitare il numero di query effettive applicate. Tutte le colonne sono indicizzate e come quelle che mi piacciono per ora, e senza prove di stress reali non posso indicizzarle ulteriormente.
Modifica: un'altra nota, sto cercando di mantenere il database il più possibile normalizzato, quindi non voglio duplicare le cose se posso evitarlo.
Dati di esempio
fonte
dbo.SupportCategories (intero):
Id StringKeyId
0 0
1 1
2 2
dbo.Languages (185 record, mostrandone solo due per esempi):
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
Uscita corrente
Data la query esatta di seguito, produce:
Result
Billing
Uscita desiderata
Idealmente, vorrei essere in grado di omettere lo specifico SupportCategories.Ide di ottenerli tutti, così (indipendentemente dal fatto che Englishfosse usata la lingua 38 , o 48 French, o QUALSIASI altra lingua al momento):
Id Result
0 Billing
1 API
2 Sales
Esempio aggiuntivo
Dato che dovevo aggiungere una localizzazione per French(cioè aggiungere 1 48 8a LanguageStringTranslations), l'output cambierebbe in (nota: questo è solo un esempio, ovviamente aggiungerei una stringa localizzata a StringTranslations) (aggiornato con l'esempio francese):
Result
Les APIs
Uscita desiderata aggiuntiva
Dato l'esempio sopra, sarebbe desiderato il seguente output (aggiornato con l'esempio francese):
Id Result
0 Billing
1 Les APIs
2 Sales
(Sì, so tecnicamente che è sbagliato dal punto di vista della coerenza, ma è ciò che sarebbe auspicabile nella situazione.)
Modificare:
Piccolo aggiornato, ho modificato la struttura della dbo.Languagestabella e lasciato cadere la Id (int)colonna da essa, sostituendola con Abbreviation(che ora è stata rinominata Ide tutte le relative chiavi esterne e le relazioni aggiornate). Da un punto di vista tecnico, questa è un'impostazione più appropriata a mio avviso a causa del fatto che la tabella è limitata ai codici ISO 639-1, che sono univoci per cominciare.
Tl; dr
Quindi: la questione, come potrei modificare questo query per restituire tutto da SupportCategoriese poi tornare sia StringTranslations.Textper quella StringKeys.Id, Languages.Idcombinazione, o il StringKeys.Namecaso lo ha fatto non esiste?
Il mio pensiero iniziale è che potrei in qualche modo trasmettere la query corrente a un altro tipo temporaneo come un'altra subquery e racchiudere questa query in un'altra SELECTenunciazione e selezionare i due campi che desidero ( SupportCategories.Ide Result).
Se non trovo nulla, farò semplicemente il metodo standard che di solito uso, che è quello di caricare tutto SupportCategoriesnel mio progetto C #, e quindi eseguo la query che ho sopra manualmente su ciascuno SupportCategories.Id.
Grazie per qualsiasi suggerimento / commento / critica.
Inoltre, mi scuso per il fatto che sia assurdamente lungo, ma non voglio alcuna ambiguità. Sono spesso su StackOverflow e vedo domande che mancano di sostanza, non volevo fare questo errore qui.
