SQL:如何从单个列中选择满足多个条件的单个id(“row”)

时间:2011-08-24 16:51:36

标签: sql select

我有一个非常狭窄的表:user_id,ancestry。

user_id列是不言自明的。

祖先栏包含用户祖先欢呼的国家/地区。

用户可以在桌面上拥有多行,因为用户可以拥有来自多个国家/地区的祖先。

我的问题是:如何选择其祖先来自多个指定国家/地区的用户?

例如,向我展示所有拥有来自英格兰,法国和德国的祖先的用户,并为每个符合该标准的用户返回1行。

那是什么SQL?

 user_id     ancestry

---------   ----------

    1        England
    1        Ireland
    2        France
    3        Germany
    3        Poland
    4        England
    4        France
    4        Germany
    5        France
    5        Germany

在上述数据的情况下,我预计结果为“4”,因为user_id 4有来自英格兰,法国和德国的祖先。

提前致谢。

P.S。澄清:是的,user_id / ancestry列创建一个唯一的对,因此不会为给定用户重复一个国家/地区。

P.P.S。我正在寻找来自所有3个国家的用户 - 英格兰,法国和德国(以及这些国家是任意的)。

P.P.P.S。我不是在寻找特定于某个RDBMS的答案。我希望“一般地”回答这个问题。

我满足于为每个查询重新生成where子句,前提是可以通过编程方式生成where子句(例如,我可以构建一个函数来构建WHERE / FROM - WHERE子句)。

9 个答案:

答案 0 :(得分:21)

试试这个:

Select user_id
from yourtable
where ancestry in ('England', 'France', 'Germany')
group by user_id
having count(user_id) = 3

最后一行表示用户的祖先拥有所有3个国家。

答案 1 :(得分:5)

3个国家/地区

之一的用户

SELECT DISTINCT user_id
FROM table
WHERE ancestry IN('England','France','Germany')

拥有所有3个国家/地区

的用户
SELECT DISTINCT A.userID
FROM table A
   INNER JOIN table B on A.user_id = B.user_id
   INNER JOIN table C on A.user_id = C.user_id
WHERE A.ancestry = 'England'
   AND B.ancestry = 'Germany'
   AND C.ancestry = 'France'

答案 2 :(得分:5)

SELECT DISTINCT (user_id) 
FROM [user]
WHERE user.user_id In (select user_id from user where ancestry = 'England') 
    And user.user_id In (select user_id from user where ancestry = 'France') 
    And user.user_id In (select user_id from user where ancestry = 'Germany');`

答案 3 :(得分:0)

第一种方式:加入:

吸引多个国家的人:

SELECT u1.user_id 
FROM users u1
JOIN users u2
on u1.user_id  = u2.user_id 
AND u1.ancestry <> u2.ancestry

从2个特定国家/地区获取人员:

SELECT u1.user_id 
FROM users u1
JOIN users u2
on u1.user_id  = u2.user_id 
WHERE u1.ancestry = 'Germany'
AND u2.ancestry = 'France'

3个国家......加入三次。只获得一次结果,不同。

第二种方式:GROUP BY

这将获得具有3行(具有...计数)的用户,然后指定允许哪些行。请注意,如果(user_id, ancestry)上没有UNIQUE KEY,则出现3次'id,england'的用户也会匹配...所以这取决于您的表结构和/或数据。

SELECT user_id 
FROM users u1
WHERE ancestry = 'Germany'
OR ancestry = 'France'
OR ancestry = 'England'
GROUP BY user_id
HAVING count(DISTINCT ancestry) = 3

答案 4 :(得分:0)

如果您希望获得满足所有条件的所有user_id,那么其中一种方法是:

SELECT DISTINCT user_id FROM table WHERE ancestry IN ('England', '...', '...') GROUP BY user_id HAVING count(*) = <number of conditions that has to be satisfied> 

等。如果您需要获取满足至少一个条件的所有user_id,那么您可以执行

SELECT DISTINCT user_id from table where ancestry IN ('England', 'France', ... , '...')

我不知道是否有类似IN的东西但是用AND而不是OR

连接条件

答案 5 :(得分:0)

蛮力(并且只在Oracle系统上测试过,但我认为这是非常标准的):

select distinct usr_id from users where user_id in (
    select user_id from (
      Select user_id, Count(User_Id) As Cc
      From users 
      GROUP BY user_id
    ) Where Cc =3
  )
  and ancestry in ('England', 'France', 'Germany')
;

编辑:我更喜欢@HuckIt的回答。

答案 6 :(得分:0)

这个问题已有几年了,但我是通过重复发表的。我也想提出一个更通用的解决方案。如果您知道您始终拥有固定数量的祖先,则可以使用一些自我联接,如答案中已建议的那样。如果你想要一个通用的方法继续阅读。

这里你需要的是关系代数中的商数。商数或多或少是笛卡尔积(或SQL中的交叉连接)的逆转。

假设您的祖先集A是(我在这里使用表格符号,我认为这对理解更好)

ancestry
-----------
'England'
'France'
'Germany'

您的用户集U

user_id
--------
   1
   2
   3

笛卡儿积C=AxU则为:

user_id  |  ancestry
---------+-----------
   1     | 'England'
   1     | 'France'
   1     | 'Germany'
   2     | 'England'
   2     | 'France'
   2     | 'Germany'
   3     | 'England'
   3     | 'France'
   3     | 'Germany'

如果你计算设定商U=C/A,那么你得到

user_id
--------
   1
   2
   3

如果您重做笛卡尔积UXA,您将再次获得C。但请注意,对于一组T(T/A)xA不一定会重现T。例如,如果T

user_id  |  ancestry
---------+-----------
   1     | 'England'
   1     | 'France'
   1     | 'Germany'
   2     | 'England'
   2     | 'France'

然后(T/A)

user_id
--------
   1
然后

(T/A)xA

user_id  |  ancestry
---------+------------
   1     | 'England'
   1     | 'France'
   1     | 'Germany'

请注意,商家和笛卡尔产品操作已消除user_id=2的记录。

您的问题是:哪个user_id有祖先所有国家/地区的祖先?换句话说,您需要U=T/A,其中T是您的原始集(或您的表)。

要在SQL中实现商,您必须执行4个步骤:

  1. 创建祖先集的笛卡尔积和集合 所有user_ids。
  2. 查找笛卡尔积中与原始集合中没有合作伙伴的所有记录(左连接)
  3. 从2)
  4. 的结果集中提取user_ids
  5. 返回原始集合中未包含在3)
  6. 结果集中的所有user_id

    让我们一步一步来做。我将使用TSQL语法(Microsoft SQL服务器),但它应该很容易适应其他DBMS。作为表(user_id, ancestry)的名称,我选择ancestor

    CREATE TABLE ancestry_set (ancestry nvarchar(25))
    INSERT INTO ancestry_set (ancestry) VALUES ('England')
    INSERT INTO ancestry_set (ancestry) VALUES ('France')
    INSERT INTO ancestry_set (ancestry) VALUES ('Germany')
    
    CREATE TABLE ancestor ([user_id] int, ancestry nvarchar(25))
    INSERT INTO ancestor ([user_id],ancestry) VALUES (1,'England')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(1,'Ireland')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(2,'France')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(3,'Germany')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(3,'Poland')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'England')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'France')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(4,'Germany')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(5,'France')
    INSERT INTO ancestor ([user_id],ancestry) VALUES(5,'Germany')
    

    1)创建祖先集的笛卡尔积和所有user_ids的集合。

    SELECT a.[user_id],s.ancestry
    FROM ancestor a, ancestry_set s
    GROUP BY a.[user_id],s.ancestry
    

    2)查找笛卡尔积中与原始集合中没有合作伙伴的所有记录(左连接)和

    3)从2)

    的结果集中提取user_ids
    SELECT DISTINCT cp.[user_id]
    FROM (SELECT a.[user_id],s.ancestry
          FROM ancestor a, ancestry_set s
          GROUP BY a.[user_id],s.ancestry) cp
       LEFT JOIN ancestor a ON cp.[user_id]=a.[user_id] AND cp.ancestry=a.ancestry
    WHERE a.[user_id] is null
    

    4)返回原始集合中未包含在3)

    结果集中的所有user_id
    SELECT DISTINCT [user_id]
    FROM ancestor
    WHERE [user_id] NOT IN (
       SELECT DISTINCT cp.[user_id]
       FROM (SELECT a.[user_id],s.ancestry
             FROM ancestor a, ancestry_set s
             GROUP BY a.[user_id],s.ancestry) cp
       LEFT JOIN ancestor a ON cp.[user_id]=a.[user_id] AND cp.ancestry=a.ancestry
       WHERE a.[user_id] is null
       )
    

答案 7 :(得分:0)

像上面的答案一样,但是我有一个重复的记录,所以我必须创建一个与众不同的子查询

public class MainViewModel
{
    public IEnumerable<Header> Headers { get; } = new Header[]
    { new Header { Value = "1" }, new Header { Value = "2" } };
    public string[,] Items { get; } = new string[2, 2] { { "1", "2" }, { "3", "4" } };
}
public class Header
{
    public string Value { get; set; }

    public override string ToString()
    {
        return Value;
    }
}

这是我使用的,因为我有多个记录(下载日志),并且它检查是否已下载所有必需的文件

答案 8 :(得分:0)

我遇到了类似您的问题,除了我想要特定的“祖先”子集。 Hong Ning的查询是一个不错的开始,只是它将返回包含重复项和/或额外祖先的合并记录(例如,它还将返回具有祖先的人(“英格兰”,“法国”,“德国”,“荷兰”)和('英格兰”,“法国”,“英国”)。假设您只需要三个,而只需要三个,则需要以下查询:

SELECT Src.user_id
FROM yourtable Src
WHERE ancestry in ('England', 'France', 'Germany')
    AND EXISTS (
        SELECT user_id
        FROM dbo.yourtable
        WHERE user_id = Src.user_id
        GROUP BY user_id
        HAVING COUNT(DISTINCT ancestry) = 3
        )
GROUP BY user_id
HAVING COUNT(DISTINCT ancestry) = 3