Sql 选择两列相同但另一列不同(如果有多个元组)的行

Sql 选择两列相同但另一列不同(如果有多个元组)的行,sql,google-bigquery,Sql,Google Bigquery,我有一个包含以下列的数据库表: local domain email_sha256 password password_sha256 a b ... C ... a bb ... C ... a bb ... CC ... a bbb ... C ... aa

我有一个包含以下列的数据库表:

local  domain  email_sha256  password  password_sha256
a      b       ...           C         ...
a      bb      ...           C         ...
a      bb      ...           CC        ...
a      bbb     ...           C         ...
aa     bb      ...           CCC       ...
aa     bb      ...           CC        ...
本地和域部分本质上是在@字符处拆分的电子邮件

test@gmail.com

本地=测试

域名=gmail.com

我想找到所有具有相同本地和密码对但具有不同域的行。这将返回类似于如果我只获取本地、域和密码列

我一直在尝试首先识别所有具有重复密码的本地密码对,包括:

SELECT local, password 
FROM tablename
GROUP BY local, password
HAVING count(*) > 1
现在,为了得到更多的列,而不仅仅是组,我对表本身进行了连接

SELECT local, domain, password 
FROM tablename
JOIN (SELECT local, domain FROM tablename GROUP BY local, password HAVING count(*) > 1)
USING (local, password)
现在,为了确保域是不同的,我再次加入表本身并添加WHERE子句。为了避免重复,我使用分组方式。这是我的最后一个问题

SELECT A.local, A.domain, A.password
FROM tablename as A
JOIN 
    (SELECT  local, domain, password 
    FROM tablename
    JOIN 
        (SELECT local, password 
        FROM tablename 
        GROUP BY local, password 
        HAVING count(*) > 1) 
    USING (local, password)) as B
USING (local, password)
WHERE A.password = B.password AND A.domain != B.domain AND A.local = B.local
GROUP BY local, domain, password
ORDER BY local, password
我是否正在删除此查询的潜在有效结果?另外,是否有更快/更好的查询可以运行并获得相同的结果

谢谢


注意:此表没有唯一的id,但我可能没有重复的电子邮件、密码和密码对,因此它们可以用作id。

下面是BigQuery标准SQL

#standardSQL
WITH remove_dup_domains AS (
  SELECT rec.* FROM (
    SELECT local, domain, password, ANY_VALUE(t) rec
    FROM `project.dataset.table` t
    GROUP BY local, domain, password
  )
)
SELECT y.* FROM (
  SELECT ARRAY_AGG(t) bin 
  FROM remove_dup_domains t
  GROUP BY local, password
  HAVING COUNT(1) > 1
)x, x.bin y
您可以使用问题中的样本数据测试、播放上述内容,如下例所示

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'a' local, 'b' domain, 'C' password, 'whatever else1' other_cols UNION ALL
  SELECT 'a', 'bb', 'C', 'whatever else2' UNION ALL
  SELECT 'a', 'bb', 'CC', 'whatever else3' UNION ALL
  SELECT 'a', 'bbb', 'C', 'whatever else4' UNION ALL
  SELECT 'a', 'bbbb', 'D', 'whatever else5' UNION ALL
  SELECT 'a', 'bbbbb', 'E', 'whatever else6' UNION ALL
  SELECT 'aa', 'bb', 'CCC', 'whatever else7' UNION ALL
  SELECT 'aa', 'bb', 'CC', 'whatever else8' UNION ALL
  SELECT 'aaa', 'com', 'H', 'whatever else9' UNION ALL
  SELECT 'aaa', 'com', 'H', 'whatever else10' 
), remove_dup_domains AS (
  SELECT rec.* FROM (
    SELECT local, domain, password, ANY_VALUE(t) rec
    FROM `project.dataset.table` t
    GROUP BY local, domain, password
  )
)
SELECT y.* FROM (
  SELECT ARRAY_AGG(t) bin 
  FROM remove_dup_domains t
  GROUP BY local, password
  HAVING COUNT(1) > 1
)x, x.bin y   
结果

Row local   domain  password    other_cols   
1   a       b       C           whatever else1   
2   a       bb      C           whatever else2   
3   a       bbb     C           whatever else4    
我想找到所有具有相同本地和密码对但具有不同域的行

我认为你可以做到:

select t.* except (min_domain, max_domain)
from (select t.*,
             min(domain) over (partition by local, password) as min_domain,
             max(domain) over (partition by local, password) as max_domain
      from tablename t
     ) t
where min_domain <> max_domain;

不!尝试使用示例数据,如选择“a”本地、“b”域、“C”密码、“whater else1”其他颜色联合所有选择“a”、“bb”、“C”、“whater else2”联合所有选择“a”、“bb”、“C”、“whater else3”联合所有选择“a”、“bbb”、“C”、“whater else4”联合所有选择“a”、“bbbbb”、“C”、“whater else5”联合所有选择“a”、“bbbbbbb”、“C”,“无论如何else6”这如何保证本地密码元组的域不同?我对具有单个域的本地域对不感兴趣。上一个选择中的x,x.biny有什么意义?如果我不想在最终表中使用ANY_值,我可以删除什么?x.bin y是UNNESTbin y的快捷方式-您可以在其中看到UNNEST和shortcut版本-upvote,如果它有助于理解此trickANY_值rec,则只需为您保留整行,以便您可以在最终结果中输出所有列。如果您只需要本地、域和密码,您可以删除该部分:A数组的要点是什么?我不明白它在做什么?另外,终于明白了ANY_值技巧我喜欢它,不再需要在我的表上使用连接!使用x,x.bin y取消设置数组的绝妙技巧,只是有点混乱,因为您以如此简洁的方式做了三件事:name table=x,unset x,将unset value重命名为y,我错了吗?我的查询似乎返回了与数组相同的值
select t.* except (min_domain, max_domain)
from (select t.*,
             min(domain) over (partition by local, password) as min_domain,
             max(domain) over (partition by local, password) as max_domain
      from tablename t
     ) t
where min_domain <> max_domain;