Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何在多个链接行中只有一行的列位于'true',其余的列位于'false'?_Mysql_Sql - Fatal编程技术网

Mysql 如何在多个链接行中只有一行的列位于'true',其余的列位于'false'?

Mysql 如何在多个链接行中只有一行的列位于'true',其余的列位于'false'?,mysql,sql,Mysql,Sql,我环顾四周,发现问题与我的问题相似,但不完全相同,因此他们得到的答案显然不适合我:( 为了尝试描绘整个画面,我有一个数据库,其中包括一个“用户”表,每个用户在另一个表“电话号码”中有一个或多个电话号码。一个用户有一个主电话号码,所以我试图通过在电话号码表中添加一个布尔列“main_number”来解决这个问题,但我无法找到一种方法来确保在一个用户的所有行中,只有一行的该列为“true” [编辑]:更准确地说,“电话号码”表记录可以按“用户Id”排序,并且在每个记录组(用户Id组)中,只有一个主号

我环顾四周,发现问题与我的问题相似,但不完全相同,因此他们得到的答案显然不适合我:(

为了尝试描绘整个画面,我有一个数据库,其中包括一个“用户”表,每个用户在另一个表“电话号码”中有一个或多个电话号码。一个用户有一个主电话号码,所以我试图通过在电话号码表中添加一个布尔列“main_number”来解决这个问题,但我无法找到一种方法来确保在一个用户的所有行中,只有一行的该列为“true”

[编辑]:更准确地说,“电话号码”表记录可以按“用户Id”排序,并且在每个记录组(用户Id组)中,只有一个主号码位于“true”。因此,“true”中的“主号码”与用户数量相同

有办法吗

对于类似的问题,我发现一般的答案是使用另一个指向主数字行的表。但这样做显然无法通过一个查询检索用户的所有行(包括第三个表中的列),除非是我的请求出错

有人能给我指出正确的方向吗


Thx

您有两种选择

选项1:用户表中的“主电话”列

只需将此列添加到表中,并将其作为主电话进行编码,“phone_Number”表中的数据作为其他可用电话进行编码

优点:易于实现。不难维护。在电话号码表中显示“主号码”列

缺点:当检索所有手机时,你需要一个连接,这将破坏所有索引的使用和查询的性能。如果你的表太大,这将是个问题

选项2:非电话号码表上的触发器

按照您的建议,添加“main_number”列。 在插入、更新和删除之前对一些触发器进行编码,以控制您的限制

插入前:

你应该控制你的限制

更新前:

应该控制你的限制。 如果删除该用户的“主电话”行(如有必要),则应控制发生的情况

删除前:

如果删除该用户的“主电话”行(如有必要),则应控制发生的情况

优点:易于检索,易于维护(一旦开发)


缺点:难以编码。

这不是一个答案,而是一个不适合评论部分的评论

尽管MySQL不支持部分索引,但我想展示如何在PostgreSQL(Oracle、SQL Server、SQLite)中实现这一点,让您知道这是可能的

例如:

create table users (
  id int not null,
  phone varchar(10) not null,
  main_number boolean not null
);

create unique index ix1 on users (id, main_number) where main_number;

insert into users (id, phone, main_number) values (1, '123', true);
insert into users (id, phone, main_number) values (1, '456', false);
insert into users (id, phone, main_number) values (1, '789', false); -- succeeds
insert into users (id, phone, main_number) values (1, '468', true); -- fails

如您所见,第三次插入成功,因为每个
id
允许多个
false
值。但是,第四次插入失败,因为每个
id
只允许一个
true
值。您可以使用唯一的约束和生成的列来执行此操作

alter table t add is_main_number boolean
    generated always as (case when main_number then 1 end);
然后,您可以在唯一索引中使用它:

create unique index unq_t_user_number_main on t(user_id, is_main_number)
MySQL允许在唯一索引中重复
NULL
值,所以这就是您想要的


是一把小提琴。

这很棘手。原因如下:

您希望每个用户都有一个主电话号码。因此,如果用户只有一个电话号码,则这是主电话号码。如果用户有四个号码,则其中一个号码必须是主号码,其他号码必须是辅助号码

…至少在提交到表时!

假设一个用户有两个条目。123456是主号码654321,是次号码。现在用户希望654321成为他们的主号码

这必须起作用:

start transaction;
update user_phone set main = true where number = '654321';
-- Just for this microsecond there are two main numbers for this user.
update user_phone set main = false where number = '123456';
commit;
-- The user has one main number again.
这是:

start transaction;
update user_phone set main = false where number = '123456';
-- Just for this microsecond there are only secondary numbers for this user.
update user_phone set main = true where number = '654321';
commit;
-- The user has one main number again.
但不是这个:

start transaction;
update user_phone set main = true where number = '654321';
commit;
-- There are two main numbers now for the user.
或者这个:

start transaction;
update user_phone set main = false where number = '123456';
commit;
-- There are only secondary numbers now for the user.
在某些DBMS中,您可以使用延迟约束来解决此问题,即仅在提交时应用的约束。在用户表中,您的电话表中还将添加一个主电话ID,然后插入一个用户,然后插入他们的电话,然后在一个事务中使用主电话更新用户。提交时,所有数据将保持一致。如果没有,则违反外键约束将触发。MySQL没有延迟约束

下面是我如何解决这个问题:给电话号码一个等级。这可以是1, 2, 3,或10, 20, 30,…实际上不重要;你会考虑最低等级号码的主要电话。
create table user_phone
(
  user_id int         not null,
  phone   varchar(20) not null,
  prio    int         not null,
  unique (user_id, phone),
  unique (user_id, prio)
);
相关查询:

select 
  user_id, phone,
  case when row_number() over (partition by user_id order by prio) = 1
       then 'main'
       else 'secondary'
  end as type
from user_phone
order by user_id, type;
如果你想让另一部手机成为主手机,那么只需改变等级即可

update user_phone set prio = prio + 1 where user_id = 1;
-- Still the same order, still the same main number.
update user_phone set prio = 1 where user_id = 1 and phone = '54321';
-- Phone '54321' is the new main number for user 1.
分析函数
ROW\u NUMBER
需要MySQL版本8。早期版本中不提供该函数


演示:

您可以创建一个函数,该函数接受用户Id和电话号码(在电话号码上)作为参数。该函数将用户的所有main_Number值更新为false,然后将传递的电话号码设置为true。这是一个常见的问题,仅凭约束是不容易解决的。在某些DBMS中,这是可能的,但我不知道是否在MySQL中。simpel解决方案是为用户表提供一个冗余的main_phone列。这很容易实现NicolaLepetit:这是我在更新数据库之前想到的java解决方案,但我发现它有点重,所以我想我应该要求另一个解决方案:)谢谢你的提示:-)@ThorstenKettner我一开始是这样做的,当时我每个用户只有一个电话号码,但是现在就像你说的,在用户表中有一个电话号码感觉是多余的:)thx作为你的提示:-)理论上这可以使用“部分索引”实现。不幸的是,MySQL没有实现它们(在MySQL行话中,有一个部分索引,但引用了一个不同的概念)。作为参考,PostgreSQL、Oracle、SQL Server甚至SQLite都支持部分索引,但不支持输入的MySQL.Thx,感觉触发器完全可以解决我这里的问题。现在要实现它:)不完全是我想要的:-)与您的