在唯一键

时间:2017-12-06 14:07:41

标签: php mysql sql

首先,这是我的代码结构和我想要实现的目标:

我有这3张桌子:

+----------------------+
| CONFIG_CAMPAIGN      |
+----------------------+
| - id_config          | 
| // other fields      |
+----------------------+

+----------------------+
| SLOT_CONFIG          |
+----------------------+
| - id_slot_config     | 
| - id_config          |
| - id_slot_pb         |
+----------------------+

+----------------------+
| SLOT_PLACE_BOX       |
+----------------------+
| - id_slot_pb         | 
| - id_place_box       |
| - date               |
| - hour               |
| - slot_available     |
+----------------------+

所以一个“slot_place_box”可以有多个“config”,一个“config”可以在多个“slot_place_box”上。我在“slot_config”上有一些触发器来根据配置更新字段“slot_available”。

现在我有一个PHP,我可以获得一些FORM数据并构建一个类似于此的SQL请求(当我遇到问题时):

INSERT INTO media.slot_place_box (id_place_box, date, hour)VALUES (32, '2017-12-10', NULL)ON DUPLICATE KEY UPDATE id_place_box = id_place_box;
SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = 32 AND SPB.date = '2017-12-10' AND SPB.hour IS NULL);
INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (125, @id);

INSERT INTO media.slot_place_box (id_place_box, date, hour)VALUES (32, '2017-12-11', NULL)ON DUPLICATE KEY UPDATE id_place_box = id_place_box;
SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = 32 AND SPB.date = '2017-12-11' AND SPB.hour IS NULL);
INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (125, @id);

INSERT INTO media.slot_place_box (id_place_box, date, hour)VALUES (32, '2017-12-12', NULL)ON DUPLICATE KEY UPDATE id_place_box = id_place_box;
SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB WHERE SPB.id_place_box = 32 AND SPB.date = '2017-12-12' AND SPB.hour IS NULL);
INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (125, @id);

// and so on

如果根据我之前在我的代码中创建的新配置没有重复,我的想法是创建一个新的“slot_place_box”+“slot_config”

OR

如果我已经有一个“slot_place_box”具有相同的“id_place_box + date + hour”,我只会使用new_config id +我已经拥有的“slot_place_box”插入一个新的“slot_config”。

我选择“INSERT ... ON DUPLICATE KEY /什么都不做/”,因为我需要我INSERT /我已经拥有的行的ID。

我在“slot_place_box”中为字段“id_place_box + date + hour”添加​​了一个UNIQUE索引键。我的问题开始是因为“小时”可以是一小时(例如“12:00:00”)但也可以是NULL(=对我而言,当NULL表示“日期”的“全天”)。当hour为NULL时,我的UNIQUE索引不起作用,因此INSERT发生了,我在数据库中有重复。

那么如何才能使这个“INSERT ... ON DUPLICATE KEY UPDATE”与具有NULL值的UNIQUE索引一起使用?

我无法使用此解决方案(here),因为我使用的是MySQl 5.6,因此我会尝试触发,因为有人在我的上一个问题(here)中建议我。

我是SQL的初学者,所以我想要一些帮助,请实现此触发器。如果我理解的话,这个想法是用触发器创建一些“虚拟”列,如果“hour”为null则在其中添加一些值+在我的UNIQUE索引中添加此虚拟列,这样ON DUPLICATE KEY就可以了。

所以我的问题是:

  • 如何在触发器中创建此“虚拟列”?
  • 如果我需要“小时”值而不是NULL,我怎样才能将这个“虚拟列”用于我的UNIQUE索引?
  • 你有更好的主意吗?

1 个答案:

答案 0 :(得分:0)

我会自己回答,但如果你们有其他解决方案,我仍然有兴趣听到它。这个解决方案对我有用,因为我正在开发一个新项目,所以它并没有真正影响我已编写的代码。

要解决此问题,我在“slot_place_box”表中添加了一个新列:

+----------------------+
| SLOT_PLACE_BOX       |
+----------------------+
| - id_slot_pb         | 
| - id_place_box       |
| - date               |
| - hour               |
| - slot_available     |
| - virtual_hour       | <- new field
+----------------------+

这个新字段是VARCHAR(10),等于“小时”,如果不是NULL(例如:“12:00:00”)或默认等于“1”或“小时”为NULL。

然后我在这个表上更改了我的UNIQUE索引“id_place_box + date + virtual_hour”,所以我永远不会得到NULL值。然后我更新我表中已有的数据:

UPDATE slot_place_box SET (virtual_hour = IF(hour is NULL, '1', hour);
// Without the safe UPDATE (I use MySQL WorkBench)

我改变了我的PHP循环以使用新列构建我的请求:

 foreach($SPB_data_array as $index => $SPB_data) {
    $current_id_pb = $SPB_data['id_pb'];
    $current_date  = $SPB_data['date'];

    if (!empty($SPB_data['hour'])) {
        $current_hour = $SPB_data['hour'];
        $sql_slot_pb .= 'INSERT INTO media.slot_place_box (id_place_box, date, hour, virtual_hour) VALUES ('. $current_id_pb .', \''. $current_date .'\', \''. $current_hour .'\', \''. $current_hour .'\')
                            ON DUPLICATE KEY UPDATE id_place_box=id_place_box;
                         SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB
                            WHERE SPB.id_place_box = '. $current_id_pb .' AND SPB.date = \''. $current_date .'\' AND SPB.hour = \''. $current_hour .'\');
                         INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (:new_config_id, @id);
                         ';
    } else {
        $sql_slot_pb .= 'INSERT INTO media.slot_place_box (id_place_box, date, hour) VALUES ('. $current_id_pb .', \''. $current_date .'\', NULL)
                            ON DUPLICATE KEY UPDATE id_place_box=id_place_box;
                         SET @id = (SELECT SPB.id_slot_pb FROM media.slot_place_box as SPB
                            WHERE SPB.id_place_box = '. $current_id_pb .' AND SPB.date = \''. $current_date .'\' AND SPB.hour IS NULL);
                         INSERT INTO media.slot_config (id_config, id_slot_pb) VALUES (:new_config_id, @id);
                         ';
    }
}

当“小时”为非空时,我刚添加第四列的“小时”值,默认情况下“virtual_hour”为“1”,因此在这种情况下无需添加。

我不知道它是否是具有大量数据的BIG项目的最佳解决方案,但在我的情况下,这是解决问题的最简单方法。