返回在列中具有相同确切项目的不同名称对

Posted

技术标签:

【中文标题】返回在列中具有相同确切项目的不同名称对【英文标题】:Return distinct pairs of names which have the same exact items in column 【发布时间】:2015-11-04 04:49:30 【问题描述】:

我想在表中找到不同的名称对,它们在项目列中具有相同的确切项目。例如:

CREATE TABLE t
(
    name    VARCHAR(255),
    item    VARCHAR(255)
);

INSERT INTO t VALUES("Alice", "Orange");
INSERT INTO t VALUES("Alice", "Pear");
INSERT INTO t VALUES("Alice", "Lemon");
INSERT INTO t VALUES("Bob", "Orange");
INSERT INTO t VALUES("Bob", "Pear");
INSERT INTO t VALUES("Bob", "Lemon");
INSERT INTO t VALUES("Charlie", "Pear");
INSERT INTO t VALUES("Charlie", "Lemon");

这里的答案是Alice,Bob,因为他们拿的东西完全相同。

我只想用双重否定(使用 NOT EXISTS/NOT IN)来做这件事,我认为这更适合这个问题,但我想不出任何离功能很近的东西。

这有点类似于this question 但我使用的是 SQLite,所以我不能使用 GROUP_CONCAT() 但我想知道如何使用 NOT EXISTS/NOT IN 的关系除法来完成.

【问题讨论】:

我给你做了一个 SQLFiddle 来玩~sqlfiddle.com/#!5/b70cd 你的桌子上有多少种不同的物品? @TimBiegeleisen 随心所欲。我认为它不会影响任何事情,只要它仍然可以返回包含完全相同的项目集的对。 SQLite 确实有 group_concat...sqlite.org/lang_aggfunc.html @Captain 好吧我的错,但我真的很想在不使用组连接的情况下获得一些解决它的提示...... 【参考方案1】:

要获取所有名称对之间的共同项目数,您可以使用以下查询:

SELECT t1.name AS name1, t2.name AS name2, COUNT(*) AS cnt
FROM t AS t1
INNER JOIN t AS t2 ON t1.item = t2.item AND t1.name < t2.name
GROUP BY t1.name, t2.name

输出:

name1   name2       cnt
------------------------
Alice   Bob         3
Alice   Charlie     2
Bob     Charlie     2

现在您要做的就是过滤掉计数不等于name1name2 的项目数的(name1, name2) 对。您可以使用带有相关子查询的 HAVING 子句来执行此操作:

SELECT t1.name AS name1, t2.name AS name2
FROM t AS t1
INNER JOIN t AS t2 ON t1.item = t2.item AND t1.name < t2.name
GROUP BY t1.name, t2.name
HAVING COUNT(*) = (SELECT COUNT(*) FROM t WHERE name = t1.name) AND 
       COUNT(*) = (SELECT COUNT(*) FROM t WHERE name = t2.name)

Demo here

【讨论】:

【参考方案2】:

与compound queries:

SELECT t1.name, t2.name
FROM t AS t1, t AS t2
GROUP BY t1.name, t2.name
HAVING t1.name < t2.name
   AND NOT EXISTS (SELECT item FROM t WHERE name = t1.name
                   EXCEPT
                   SELECT item FROM t WHERE name = t2.name)
   AND NOT EXISTS (SELECT item FROM t WHERE name = t2.name
                   EXCEPT
                   SELECT item FROM t WHERE name = t1.name);

使用 NOT IN 是可能的,bit 表示完全相同的机制,但更复杂:

SELECT t1.name, t2.name
FROM t AS t1, t AS t2
GROUP BY t1.name, t2.name
HAVING t1.name < t2.name
   AND NOT EXISTS (SELECT item
                   FROM t
                   WHERE name = t1.name
                     AND item NOT IN (SELECT item
                                      FROM t
                                      WHERE name = t2.name))
   AND NOT EXISTS (SELECT item
                   FROM t
                   WHERE name = t2.name
                     AND item NOT IN (SELECT item
                                      FROM t
                                      WHERE name = t1.name));

【讨论】:

【参考方案3】:

这似乎适用于 SQLLite

    select t1.name
    from t t1
        join t t2 on t1.name <> t2.name and t1.item = t2.item 
        join (select name, count(*) as cnt from t group by name) t3 on t3.name = t1.name
        join (select name, count(*) as cnt from t group by name) t4 on t4.name = t2.name
    group by t1.name, t3.cnt, t4.cnt
    having count(*) = max(t3.cnt, t4.cnt)

【讨论】:

【参考方案4】:

我可能已经找到了解决您问题的方法。我的使用 mysql 进行了测试,但没有使用 GROUP_CONCAT()。它可能适用于您的 SQLite 数据库。我的查询用于查找购买过相同商品的人。

尝试使用以下语句: SELECT DISTINCT e1.name, e2.name from t e1, t e2 WHERE e1.item=e2.item AND e1.name != e2.name GROUP BY e1.item HAVING count(*) >1;

https://gyazo.com/5e5e9d0ddfb33cb47439a674297108ed

【讨论】:

以上是关于返回在列中具有相同确切项目的不同名称对的主要内容,如果未能解决你的问题,请参考以下文章

我不能在列中添加具有 2 个相同值的行

两列布局,无需JavaScript即可重新排序项目

VS Code:对具有相同名称和不同扩展名的文件进行分组

WPF DataGrid在同一列中的不同控件 - 不正确的绑定

C#中具有相同名称和签名但返回类型不同的方法

在列中显示两个不同日期的数据