Mysql,作为1个查询,如果行不存在,则执行其他查询

时间:2011-08-09 22:32:39

标签: mysql

对于偏好模块,我有“系统默认值”和“用户首选项” 如果没有存储个人/用户偏好,则改为使用系统默认值。

这是我的系统偏好表:

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,以及其他所有人。我通过这个例子学到了一些东西。

2 个答案:

答案 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);