0

我对 SQL 很陌生,并且在我的表中使用外键时遇到了一些麻烦——插入/更新此类表的单行需要大量查询。

所以,基本上我有一个由 4 个表组成的结构,用于存储 IRC 频道的“key = value”关系:

msg
  -id integer //primary key
  -srv_id     //integer
  -chan_id    //integer
  -usr_id     //integer
  -key        //text
  -value      //text

.

srv
  -id   //integer primary key
  -name //text

.

chan
  -id   //integer primary key
  -name //text

.

usr
  -id   //integer primary key
  -name //text

msg 表中的 srv_id、chan_id 和 usr_id 是接下来三个表的外键。

我需要注意的是,用户可以覆盖其他人的键,因此当用户添加“键 = 值”关系时,我需要在 msg 表中插入新行或更新给定 srv_name、chan_name 和键的现有值和 usr_name。

问题:知道:msg.key = 'some_msg_key', msg.value = 'new_msg_value', srv.name = 'some_srv_name', chan 如何有效地添加一行(或者如果给定的键已经存在于 msg 表中则更新它) .name = 'some_chan_name' 和 usr.name = 'some_usr_name' 可能尚未出现在表中。

现在我正在做这样的事情:

SELECT id FROM srv WHERE name = 'some_srv_name'

检查我是否有 id,如果没有,我会

INSERT INTO srv WHERE name = 'some_srv_name'

然后我得到它的ID

SELECT id FROM srv WHERE name = 'some_srv_name'

然后我对 chan 表和 usr 表做同样的事情。
当 srv、chan 和 urs 名称是全新的时,这是 9 个查询。这不是很可怕吗?这还不是结束——我的目标是向 msg 表添加新行或更新它(如果存在)(基于键值)。

所以,当我知道 'some_srv_name'、'some_chan_name' 和 'some_usr_name' 在表中并且我得到了它们的 id 时,我检查是否存在具有此类 id 和键值 = 'some_msg_key' 的行:

SELECT id FROM msg WHERE srv_id = 'id_from_previous_queries' AND chan_id = 'id_from_previous_queries' AND key = 'some_msg_key'

如果我得到任何东西,我知道该行存在并且我需要更新它,所以我这样做:

UPDATE msg SET usr_id = 'id_from_previous_queries', key = 'some_msg_key', value = 'new_msg_value' WHERE id = 'id_from_right_above'

如果我什么也没得到,我知道没有这样的行,我需要插入它:

INSERT INTO msg VALUES(null, 'id_from_previous_queries', 'id_from_previous_queries', 'id_from_previous_queries', 'some_msg_key', 'new_msg_value')

所以,我总共做了 5-11 个查询。

我想知道是否有更好的方法来减少查询数量来添加/更新 msg 表中的一行,只知道可能不在表中的 srv、chan 和 usr 的名称。

注意:我使用 SQLite

4

2 回答 2

1

是的,您可以更轻松地做到这一点。首先构建查找表,然后构建最终的 msg 表。假设您在表 src 中有非规范化数据,并且您想要插入它。

首先,您必须使用以下查询向每个查找表中插入新值:

insert into srv(name)
    select distinct name
    from src
    where name not in (select name from srv)

应该通过将 id 声明为自动增量/标识/序列列(取决于您的数据库)来自动分配 id。

对每个查找表执行此操作。然后执行以下操作以插入 msg 表:

insert into msg(srv_id, chan_id, usr_id, key, value)
    select srv.srv_id, chan.chan_id, . . . 
    from src join
         srv
         on src.name = srv.src_name join
         chan
         on chan.name = srv.chan_name . . .
于 2012-07-09T14:49:08.180 回答
0

您不必更改主键的值。您应该查找如何使用存储过程和触发器。

于 2012-07-09T14:47:18.160 回答