修改
我已经包含了create语句和一小组测试数据供您试用。因此,我已将示例id
更改为2
而不是5
,以表示测试数据中的现有id
。
/ edit
我有三个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');
困境:
要检索具有id 2
所有活动语言环境的页面,请发出以下SQL语句:
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
不可用于特定区域设置时,它会自动回退到该区域设置的根页面(即:page.parentId IS NULL
)?我的目标是让MySQL为活动区域设置提供一个,但不是两个。
我试过了:
WHERE
(p.id = '2' OR (p.parentId IS NULL))
但是,当然,这给了我两个实际上也有id 2
的语言环境记录。我很确定它是可能的(使用UNION
,子选择或页面上的重复连接)但是我在这里有一个完整的SQL编写器块。我很感激你的帮助。
答案 0 :(得分:0)
XOR怎么样? “一个或另一个但不是两个”:
WHERE
(p.id = '5' XOR (p.parentId IS NULL))
^---here
答案 1 :(得分:0)
使用LEFT JOIN并将两个表连接两次。第二次加入专门针对p.parentId IS NULL
的情况。
在SELECT列表中使用IFNULLs。第一个参数用于指定的id
,第二个参数是回退,即根页的值。
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')
答案 2 :(得分: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