2

編集:

試してみるために、createステートメントとテストデータの小さなセットを含めました。そのため、テストデータに存在するものを表す代わりに、例idをに変更しました。25id

/ 編集

ローカライズされたページ情報を保持するための3つのMySQLテーブルがあります。

CREATE TABLE `locale` (
  `languageCode` char(3) NOT NULL,
  `regionCode` char(3) NOT NULL default 'ZZ',
  `isActive` enum('yes','no') NOT NULL default 'no',
  PRIMARY KEY  (`languageCode`,`regionCode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `page` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `parentId` int(10) unsigned default NULL,
  PRIMARY KEY  (`id`),
  KEY `FK_page_page_1` (`parentId`),
  CONSTRAINT `FK_page_page_1` FOREIGN KEY (`parentId`) REFERENCES `page` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `pageInfo` (
  `pageId` int(10) unsigned NOT NULL,
  `languageCode` char(3) NOT NULL,
  `regionCode` char(3) NOT NULL default 'ZZ',
  PRIMARY KEY  (`pageId`,`languageCode`,`regionCode`),
  KEY `FK_pageInfo_locale_1` (`languageCode`,`regionCode`),
  KEY `FK_pageInfo_page_1` (`pageId`),
  CONSTRAINT `FK_pageInfo_locale_1` FOREIGN KEY (`languageCode`, `regionCode`) REFERENCES `locale` (`languageCode`, `regionCode`) ON DELETE CASCADE,
  CONSTRAINT `FK_pageInfo_page_1` FOREIGN KEY (`pageId`) REFERENCES `page` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

そしてここにいくつかのテストデータがあります:

/* locale */
INSERT INTO `locale` (languageCode,regionCode,isActive) VALUES ('de','ZZ','yes');
INSERT INTO `locale` (languageCode,regionCode,isActive) VALUES ('en','ZZ','yes');
INSERT INTO `locale` (languageCode,regionCode,isActive) VALUES ('nl','ZZ','yes');
/* page */
INSERT INTO `page` (id,parentId) VALUES (1,NULL);
INSERT INTO `page` (id,parentId) VALUES (2,1);
/* pageInfo */
INSERT INTO `pageInfo` (pageId,languageCode,regionCode) VALUES (1,'de','ZZ');
INSERT INTO `pageInfo` (pageId,languageCode,regionCode) VALUES (1,'en','ZZ');
INSERT INTO `pageInfo` (pageId,languageCode,regionCode) VALUES (1,'nl','ZZ');
INSERT INTO `pageInfo` (pageId,languageCode,regionCode) VALUES (2,'en','ZZ');
INSERT INTO `pageInfo` (pageId,languageCode,regionCode) VALUES (2,'nl','ZZ');

ジレンマ:すべてのアクティブなロケールの
ページを取得するには、次のSQLステートメントを発行します。id 2

SELECT 
        p.*,   pi.languageCode,   pi.regionCode
    FROM
        page AS p
        INNER JOIN pageInfo AS pi
            ON pi.pageId = p.id
        INNER JOIN locale AS l
            ON l.languageCode = pi.languageCode AND l.regionCode = pi.regionCode
    WHERE
        (p.id = '2')
        AND (l.isActive = 'yes')

このステートメントを変更してid 2、特定のロケールで使用できない場合に、そのロケールのルートページ(つまり、where page.parentId IS NULL)に自動的にフォールバックするようにするにはどうすればよいですか?私の目標は、MySQLにアクティブなロケールに対してどちらか一方(両方ではない)を提供させることです。

私は試した:

WHERE
    (p.id = '2' OR (p.parentId IS NULL))

しかし、もちろん、それは私に実際にid 2も持っているロケールの2つのレコードを与えます。私はそれが可能であるとかなり確信しています(UNION、サブ選択、またはページ上の重複結合のいずれかで)が、ここでは合計SQLライターブロックがあります。よろしくお願いします。

4

3 に答える 3

0

LEFT JOINを使用して、両方のテーブルを2回結合します。2回目は、特に。の場合に参加しますp.parentId IS NULL

SELECTリストでIFNULLを使用します。最初の引数はid指定されたものに対するものであり、2番目の引数はフォールバック、つまりルートページの値です。

SELECT
    p.*,
    IFNULL(l.languageCode, lr.LanguageCode) AS languageCode,
    IFNULL(l.regionCode, lr.regionCode) AS regionCode
FROM
    page AS p
    LEFT JOIN pageInfo AS pi
        ON pi.pageId = p.id
    LEFT JOIN locale AS l
        ON l.languageCode = pi.languageCode AND l.regionCode = pi.regionCode
    LEFT JOIN pageInfo AS pir
        ON pir.pageId = p.id AND p.parentId IS NULL
    LEFT JOIN locale AS lr
        ON lr.languageCode = pir.languageCode AND lr.regionCode = pir.regionCode
WHERE
    (p.id = '5' AND l.isActive = 'yes')
    OR (p.parentId IS NULL AND lr.isActive = 'yes')
于 2011-02-14T00:13:53.187 に答える
0

XORはどうですか?「どちらか一方、両方ではない」:

WHERE
    (p.id = '5' XOR (p.parentId IS NULL))
                ^---here
于 2011-02-13T17:19:17.543 に答える
0

p.id=5 で注文し、1 の制限を使用することもできます。これは少しハックですが、うまくいきます。

SELECT 
        p.*,   pi.languageCode,   pi.regionCode
    FROM
        page AS p
        INNER JOIN pageInfo AS pi
            ON pi.pageId = p.id
        INNER JOIN locale AS l
            ON l.languageCode = pi.languageCode AND l.regionCode = pi.regionCode
    WHERE
        (p.id = '5' OR (p.parentId IS NULL))
        AND (l.isActive = 'yes')
    ORDER BY p.id = '5' DESC
    LIMIT 1
于 2011-02-14T01:45:55.003 に答える