【问题标题】:Delete rows from table with no primary key, SQL从没有主键的表中删除行,SQL
【发布时间】:2013-08-23 00:20:53
【问题描述】:

我正在尝试从 SQL 中的表中删除几行。问题是我无法弄清楚如何使用子查询的结果从该表中删除,因为该表中没有主键。表结构如下:

Friend ( ID1, ID2 )

ID1 的学生是ID2 的学生的朋友。友谊是相互的,所以如果(123, 456) 在Friend 表中,那么(456, 123) 也是。

Likes ( ID1, ID2 )

ID1 的学生喜欢ID2 的学生。喜欢某人不一定是相互的,所以如果 (123, 456) 在 Likes 表中,则不能保证 (456, 123) 也存在。

(No primary key)

我要解决的情况是:

“如果两个学生 A 和 B 是朋友,并且 A 喜欢 B 但反之不喜欢,则删除 Likes 元组。”

提前致谢。

【问题讨论】:

  • 哪个数据库? Mysql、Postgres、SQL Server?
  • 如果 Likes 中有重复行,学生 A like 是否喜欢学生 B?
  • @supergrady,A学生只喜欢B一次,即没有条件像A喜欢B两次,但A可以喜欢更多的人喜欢C或D。

标签: sql sqlite


【解决方案1】:

要解决您的问题,请使用以下 sql 查询

delete from friend where (ID1,ID2)  not in
(Select f1.ID1,f1.ID2 from friend f1, friend f2 where f1.ID1 = f2.ID2 && f1.ID2 = f2.ID1)

如果您的数据库不支持“in”子句中的多列,请使用以下查询

delete from friend where concat(ID1,':',ID2)  not in
(Select concat(f1.ID1,':',f1.ID2) from friend f1, friend f2 
where f1.ID1 = f2.ID2 && f1.ID2 = f2.ID1)

我们可以将 ID1 和 ID2 的组合视为复合主键吗?

最好始终在每个表中使用主键。 请使用整数自动递增字段将主键添加到您的表中,这将很容易解决您的问题

【讨论】:

  • 表格数据已提供,不可修改。因此,无法添加或修改唯一或复合主键。但是,是的,ID1 和 ID2 对是唯一的,因为一个人不可能喜欢另一个人两次。
  • 问题是我们不能使用“in”对 where 子句进行多列检查。
  • 我们可以在“in”子句中添加多列,请查看stackoverflow.com/questions/13027708/…
  • 我想你在这里漏了一点,我们必须检查单向喜欢,而不是单向友谊
【解决方案2】:

非常有趣的问题:-

我在这里创建您的表格并尝试创建相同的场景,然后我找到了解决方案。 希望对你有帮助...

 CREATE TABLE friends
  (
     id1 NUMERIC,
     id2 NUMERIC
  );

CREATE TABLE likes
  (
     id1 NUMERIC,
     id2 NUMERIC
  );

INSERT INTO friends
VALUES      (1,
             2);

INSERT INTO friends
VALUES      (2,
             1);

INSERT INTO friends
VALUES      (1,
             3);

INSERT INTO friends
VALUES      (3,
             1);

INSERT INTO friends
VALUES      (3,
             2);

INSERT INTO friends
VALUES      (2,
             3);

INSERT INTO likes
VALUES      (1,
             2);

INSERT INTO likes
VALUES      (2,
             1);

INSERT INTO likes
VALUES      (1,
             3);

INSERT INTO likes
VALUES      (3,
             1);

INSERT INTO likes
VALUES      (2,
             3);

SELECT *
FROM   friends

SELECT *
FROM   likes

SELECT *
FROM   likes A
WHERE  NOT EXISTS (SELECT 1
                   FROM   likes B
                   WHERE  A.id1 = B.id2
                          AND A.id2 = B.id1
                          AND EXISTS (SELECT 1
                                      FROM   friends
                                      WHERE  A.id1 = friends.id1
                                             AND A.id2 = friends.id2));

您的删除查询将是...

 DELETE A
    FROM   likes AS A
    WHERE  NOT EXISTS (SELECT 1
                       FROM   likes B
                       WHERE  A.id1 = B.id2
                              AND A.id2 = B.id1
                              AND EXISTS (SELECT 1
                                          FROM   friends
                                          WHERE  A.id1 = friends.id1
                                                 AND A.id2 = friends.id2));  

【讨论】:

  • @user2709226 告诉我...我的回答对您有帮助吗?
  • 感谢您尝试@hardikvinzava,但正如我已经提到的,我的平台是 SQLite,所以它使用的是 SQL 服务器。它显示了使用“A”的语法错误,因为我们不能为要从中删除的表使用别名。
【解决方案3】:

在大多数 SQL 方言中,您可以这样做:

delete from likes
    where not exists (select 1 from likes l2 where l2.id1 = likes.id2 and l2.id2 = likes.id1) and
          exists (select 1 from friends f where f.id1 = likes.id1 and f.id2 = likes.id2);

这几乎是您的两个条件的直接翻译。

【讨论】:

  • 你为什么要加入朋友圈?当然,即使朋友表存在,也可以建立不存在。
  • @Bohemian 。 . .这满足条件“如果两个学生 A 和 B 是朋友”。 not exists 子句满足“A 喜欢 B 但反之不行”。
  • 这里给出的答案@GordonLinoff 删除了比需要更多的行。这可能是因为仅根据 ID1 而非 ID1 和 ID2 对来检查存在性。请记住,我们不能仅通过 ID1 唯一标识一行。在这种情况下,我想我们也会删除 ID1 对其他人的喜欢。
  • @user2709226 。 . .我只签了一个方向(在朋友身上,因为你明确地说“朋友”关系是双向的。
  • 我知道,@GordonLinoff ,但你的解决方案。删除比需要更多的行。据我说,您在声明中使用了 likes.id2。因此,它不会获取被认为被删除的 ID 组,而是仅使用第一个 ID1,并从新表中选择 ID2。这会选择比需要更多的行。
【解决方案4】:

我试图为这个问题制定一个答案。它适用于我的小测试数据,但请指出它对于大数据是否可能效率低下,或者如何通过更好的解决方案使其变得更好。

Delete from Likes where
ID1 in (select Q.ID1
from (select x.ID1, x.ID2
from (select A.ID1,A.ID2,B.ID2 as se
from Likes A left join Likes B
on A.ID2=B.ID1) x where x.ID1 <> x.se or x.se is null) Q inner join Friend F
where Q.ID1 = F.ID1 and Q.ID2 = F.ID2 order by Q.ID1)

and ID2 in  (select Q.ID2
from (select x.ID1, x.ID2
from (select A.ID1,A.ID2,B.ID2 as se
from Likes A left join Likes B
on A.ID2=B.ID1) x where x.ID1 <> x.se or x.se is null) Q inner join Friend F
where Q.ID1 = F.ID1 and Q.ID2 = F.ID2 order by Q.ID1)

【讨论】:

    【解决方案5】:

    通过连接将两列表示为一个值,然后使用反向组合的NOT IN ()

    delete from likes
    where id1 || ' ' || id2 not in (select id2 || ' ' || id1 from likes);
    

    在 SQLFiddle 上查看 live demo,表明此查询确实有效。

    【讨论】:

    • 感谢您的试用。但是问题需要一个与您提供的完全不同的解决方案。我们必须检查单向喜欢,考虑他们是否是朋友。只有当他们是朋友时我们才需要删除,但只有一个喜欢另一个。
    猜你喜欢
    • 2010-11-02
    • 2017-03-14
    • 2012-01-19
    • 1970-01-01
    • 2017-08-17
    • 1970-01-01
    • 1970-01-01
    • 2017-02-12
    相关资源
    最近更新 更多