对于偏好模块,我有“系统默认值”和“用户首选项” 如果没有存储个人/用户偏好,则改为使用系统默认值。
这是我的系统偏好表:
mysql> desc rbl;
+-------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+-------+
| id | varchar(3) | NO | PRI | | |
| rbl_url | varchar(100) | NO | | | |
| description | varchar(100) | NO | | | |
| is_default | tinyint(1) unsigned | YES | | 1 | |
+-------------+---------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
来自系统首选项的示例数据:
mysql> select * from rbl;
+----+----------------------+------------------------------+------------+
| id | rbl_url | description | is_default |
+----+----------------------+------------------------------+------------+
| 1 | sbl-xbl.spamhaus.org | Spamhaus SBL-XBL | 1 |
| 2 | pbl.spamhaus.org | Spamhaus PBL | 1 |
| 3 | bl.spamcop.net | Spamcop Blacklist | 1 |
| 4 | rbl.example.com | Example RBL - not functional | 0 |
+----+----------------------+------------------------------+------------+
...和查询系统默认值:
mysql> SELECT rbl_url FROM rbl WHERE is_default='1';
+----------------------+
| rbl_url |
+----------------------+
| sbl-xbl.spamhaus.org |
| pbl.spamhaus.org |
| bl.spamcop.net |
+----------------------+
3 rows in set (0.01 sec)
到目前为止一切顺利。 好。现在我需要一个用户首选项表,我想出了这个:
mysql> desc rbl_pref;
+-----------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-----------------------+------+-----+---------+----------------+
| id | mediumint(8) unsigned | NO | PRI | NULL | auto_increment |
| domain_id | mediumint(8) unsigned | NO | | NULL | |
| rbl_id | tinyint(1) unsigned | NO | | NULL | |
+-----------+-----------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
(仅供参考 - “用户”由“domain_id”表示。)
让我们查看已保存个性化偏好的特定用户的偏好设置:
mysql> select * from rbl_pref where domain_id='2277';
+----+-----------+--------+
| id | domain_id | rbl_id |
+----+-----------+--------+
| 4 | 2277 | 1 |
| 5 | 2277 | 2 |
| 6 | 2277 | 4 |
+----+-----------+--------+
3 rows in set (0.00 sec)
......再次,但格式更简单:
mysql> SELECT rbl.rbl_url FROM rbl_pref,rbl
WHERE rbl_pref.rbl_id=rbl.id AND domain_id='2277';
+----------------------+
| rbl_url |
+----------------------+
| sbl-xbl.spamhaus.org |
| pbl.spamhaus.org |
| rbl.example.com |
+----------------------+
3 rows in set (0.00 sec)
..到目前为止一切顺利。如果用户已存储首选项,则会找到结果。
现在的问题是,用户1999没有自定义首选项。 代替“空集”结果,我想要系统默认值。
mysql> SELECT rbl.rbl_url FROM rbl_pref,rbl
WHERE rbl_pref.rbl_id=rbl.id AND domain_id='1999';
Empty set (0.00 sec)
我很高兴能找到一个非常相似的问题: mysql if row doesn't exist, grab default value 但是经过几天的试错和文档审核后,我无法将这个答案翻译到此处。
与上述问题类似,这必须作为单个MySQL查询完成。我实际上并不是从PHP进行这个查询,而是从Exim宏开始(这是一种非常挑剔的语言...最好将它作为变量赋值给它“一个衬里”,因为我试着在这里做..)
更新:尝试了下面@Biff McGriff建议的一种UNION查询。该表没有显示在我的评论回复中,所以这里又是:
mysql> SELECT rbl.rbl_url FROM rbl_pref,rbl
WHERE rbl_pref.rbl_id=rbl.id AND domain_id='2277'
UNION SELECT rbl_url FROM rbl WHERE is_default='1';
+----------------------+
| rbl_url |
+----------------------+
| sbl-xbl.spamhaus.org |
| pbl.spamhaus.org |
| rbl.example.com |
| bl.spamcop.net |
+----------------------+
4 rows in set (0.00 sec)
正如您在上面所看到的,用户2277没有选择加入rbl_id 3(bl.spamcop.net),但无论如何都会出现。
我的UNION查询似乎要做的是组合结果集。所以user_pref充当“除了”全局默认值之外,我假设/期望我得到一个与查询的一半匹配的结果集。
所以现在我的问题是,更好(或可能,如何)将其解决为“结果集”(UNION两侧的子查询)?或者我真的需要一个关于rbl_pref的新字段,例如称为“enabled”。后者似乎更正确 - 我需要在rbl_pref中明确指定opt-in或opt-out(除了隐含的“pref不在这里 - 没有rbl_id = 3 - 在过度使用的用户结果SET中”)
更新:全部设置,谢谢@Imre L,以及其他所有人。我通过这个例子学到了一些东西。
答案 0 :(得分:3)
您应该可以使用左连接,然后使用默认字段coalesce用户的字段。
答案 1 :(得分:1)
注意:您必须在两个地方输入domain_id
。
SELECT rbl.rbl_url FROM rbl
JOIN rbl_pref ON rbl_pref.rbl_id=rbl.id AND domain_id=2277
UNION
SELECT rbl.rbl_url FROM rbl
WHERE rbl.is_default
AND NOT EXISTS (SELECT 1 FROM rbl_pref WHERE domain_id=2277 LIMIT 1)
;
现在UNION
的一方或另一方将使用impossible where
您也不应将varchar(3)
用于rbl.id
,而应使用某种整数
和rbl_pref.rbl_id
太小的tinyint
相似的类型
当你比较sql代码domain_id='2277'
中的整数字段时,你不应该在常量整数周围使用'
或"
。
你可以大部分时间离开它,但有时它可能会混淆mysql优化器。
为了获得最佳性能和一致性,我建议您添加索引:
ALTER TABLE rbl_pref
ADD UNIQUE INDEX ux_domain_rbl (domain_id, rbl_id);