web-dev-qa-db-ja.com

スーパータイプ-サブタイプの国際化

まず第一に、この質問を別の質問と結び付けてしまったことをお詫びしますが、それは私がそれを単純で集中的に保つために考えることができる最良の方法でした

数ヶ月前 多かれ少なかれ提示しやすい問題の解決策としてスーパータイプサブタイプを紹介されましたが、解決できませんでした

基本的な概念を理解し、適度な知識でそれを機能させることができました。元の質問が1年以上前のものであることを考えると、非常にうまく機能しました。

しかし、今日、私は解決できない問題に直面しました:国際化

これまで、すべてのサブタイプ(ItemsCar、およびBoat)と同じように、スーパータイプテーブル(Plane)のPRIMARYKEYを指すFOREIGNKEYを持つi18nという名前のテーブルがあり、クエリを実行すると、すべてのサブタイプのすべての列の中で、この国際化テーブルに、スーパータイプキーですべてを結合する翻訳された文字列を含む列を含めます。

このようなもの:

Items構造:

+----+---------------------+---------------------+
| PK | Common Attribute #1 | Common Attribute #2 |
+----+---------------------+---------------------+

Car構造:

+----+-----------+--------------+--------------+
| PK | Reference | Attribute #1 | Attribute #2 |
+----+-----------+--------------+--------------+

Boat構造:

+----+-----------+--------------+--------------+--------------+
| PK | Reference | Attribute #1 | Attribute #2 | Attribute #3 |
+----+-----------+--------------+--------------+--------------+

Plane構造:

+----+-----------+--------------+--------------+--------------+--------------+
| PK | Reference | Attribute #1 | Attribute #2 | Attribute #3 | Attribute #4 |
+----+-----------+--------------+--------------+--------------+--------------+

i18n構造:

+----+-----------+------+
| PK | Reference | Text |
+----+-----------+------+

Referenceは外部キーです

これが最善のアプローチであるかどうかは正確にはわかりませんが、これまでは1つの列のみが国際化の受動的なテキストを持っていたため、機能します。たとえば、Attribute #1とします。しかし、今日、サブタイプの1つを変換するために2つの列が必要であり、私が行っていた方法では1つだけを考慮していることに気付きました。たとえばPlanesテーブルのAttribute #4です。

サーバーサイド言語に置き換える代表的なキーワードではなく、データベースレベルでこれを実行したいと思います。

この2番目の列を翻訳するためのサブクエリを作成しようとしましたが、機能しなかっただけでなく、悪臭を放っていました。

どうすればこれを行うことができますか?

[編集]

私は最後の試みを投稿するために最善を尽くしたと思いました:

SELECT 
    `items`.`cid` AS `id`, `items`.`reference`, `items`.`GUID`,     # That's Users' Items Table

    `core`.`image`, `core`.`type`, `core`.`class` AS `classname`,   # That's the supertype

    `cars`.`attribute1`, `cars`.`attribute2`,

    `boats`.`attribute1`, `boats`.`attribute2`, `boats`.`attribute3`,

    `planes`.`attribute1`, `planes`.`attribute2`, `planes`.`attribute3`, `planes`.`attribute4`,

FROM `items`
    LEFT OUTER JOIN core ON( ( items.reference = core.iid ) )
        LEFT OUTER JOIN `catalog`.`cars` cars ON( items.reference = cars.reference )
            LEFT OUTER JOIN `catalog`.`boats` boats ON( items.reference = boats.reference OR items.reference = boats.attribute3 )
                LEFT OUTER JOIN `catalog`.`planes` planes ON( items.reference = planes.reference )
                    LEFT OUTER JOIN users ON( items.UserId = users.id )
                        LEFT OUTER JOIN i18n ON( items.reference = i18n.reference )

WHERE `i18n`.`langCode` = 'en'
        AND ( `items`.`GUID` = '4cca0b05-84b0-40af-8808-2379b32df35f' OR `items`.`GUID` = '41a0917e-8ccf-43a3-b52a-0ae0a09a2374' )

ORDER BY ( FIELD( `items`.`GUID`, '4cca0b05-84b0-40af-8808-2379b32df35f','41a0917e-8ccf-43a3-b52a-0ae0a09a2374' ) )

この例では、サブタイプBoatsを使用して、翻訳できる/翻訳する必要がある他の列を示しました。

このクエリを使用すると、すべてのサブタイプに必要なすべてのデータを一度に取得できます。 NULLとしていくつかの列がありますが、データをフェッチするときは、PHP(PDO::FETCH_NAMED、重要なこと))ですべてが機能します。

しかし、テキスト(i18n.text)を含む列を返すことはできず、スーパータイプテーブル(Items.reference)と一致する参照IDのみを返すことができます。

取得する列として含めていないことはわかっていますが、含めた場合、最初の翻訳可能な列(attribute1)は機能しますが、それ以外の場合は、任意のサブタイプが持つ可能性があります(ここではboats.attribute3)は、独自の参照値を取得する代わりに、atribute1の値を複製します。

2
user5613506

個人的には、テキスト値の国際バリアントを取得するために複数のテーブルを結合する必要がないため、国際化する必要のある各属性をXML列またはJSON列のいずれかに作成し、関連する関数を使用して言語に一致する値を返します。必要。これは、新しいテーブルを追加せずに複数の言語を非常に簡単に追加できるという意味で非常に拡張可能なソリューションですが、それに対処するために挿入、更新、および選択を変更する必要があります。

XMLの例:

'<?xml version="1.0"?>
 <translations>
    <text key="en-US" value="pants"/>
    <text key="en-UK" value="trousers"/>
 </translations>'

SELECT ExtractValue([column], '/translations/text[@key="en-US"]');

JSONの例:

'{
    "en-US" : "pants",
    "en-UK" : "trousers"
 }'

SELECT JSON_EXTRACT([column], '$."en-US"');

消費するストレージが少ないため、JSONを使用することを好みますが、どちらのアプローチも、データベースをルックアップテーブルでいっぱいにするよりも優れていると思います。 UnicodeをサポートするXMLまたはJSONの文字セットを使用していることを確認する必要があります。

3
Mr.Brownstone

文字セット?

今日はすべてのVARCHARlatin1だと言っていますか?しかし、明日はutf8mb4が必要ですか?

プランA:

  1. 外部キーを無効にする
  2. ALTER TABLE ... CHARACTER SET utf8mb4
  3. FKを有効にします。

次の手段:

  1. スキーマをダンプします。文字セットを手動で変更する
  2. スキーマなしでデータをダンプする
  3. 新しいマシンでスキーマをロードし、次にデータをロードします

注意:「悪魔は細部にある」。

フレーズ?

今日は英語のフレーズがたくさんあるが、明日は複数の言語の各フレーズが必要になると言っている場合は、文字セットを変更するだけでなく、やるべきことがたくさんあります。

  • 言語に依存しないIDを持つようにフレーズを変更します。
  • これらのIDを各言語にマップするルックアップテーブルを用意します(phrase_idlanguagephrase
  • EN-USEN-UKなどの標準の5文字(ASCII)言語を提案します。これらに個別のIDを作成する必要はなく、そのまま使用してください。
  • 適切なフレーズを選択するための一連のコードを記述します。
2
Rick James