sqlite 如何在SQL中从每个家庭中选择一个孩子?

y53ybaqx  于 2023-06-23  发布在  SQLite
关注(0)|答案(3)|浏览(141)

我使用SQLite并有一个包含名称列表的表,其中一些是同一家族的成员。

'-----------------------------------'
| Id | Last Name | First Name | Age |
------------------------------------|
| 1  | Gordon    | James      |  5  |
| 2  | Gordon    | Mike       | 19  |
| 3  | Gordon    | Sara       |  8  |
| 4  | Gordon    | Cludia     | 25  |
| 5  | Sagget    | Bob        | 22  |
| 6  | Saywer    | Tom        |  9  |
| 7  | Saywer    | Jean       | 20  |
| 8  | Finn      | Hucklberry |  8  |
| 9  | Smith     | John       | 18  |
| 10 | Smith     | Sue        | 39  |
'-----------------------------------'

我需要选择所有18岁或以上的人,但只从每个家庭中挑选一名成员。查询应该选择年龄大于或等于18岁的最年轻的人。对于上面的示例,查询应该返回以下人员:

'-----------------------------------'
| Id | Last Name | First Name | Age |
------------------------------------|
| 2  | Gordon    | Mike       | 19  |
| 5  | Sagget    | Bob        | 22  |
| 7  | Saywer    | Jean       | 20  |
| 9  | Smith     | John       | 18  |
'-----------------------------------'

请注意,Hucklberry Finn不是输出的一部分,因为他不满足18岁或更大的条件,并且他没有兄弟姐妹或亲戚:(。因此,没有“芬兰人”被选中。
实现上述结果的最简单的查询是什么?
以下是我尝试的:

SELECT
    id,
    last_name,
    first_name,
    age
FROM
    people p
WHERE
    age >= 18
    and age < (
      select min(age) from people where age > 18 and last_name = p.last_name
)

我觉得一定有比我的尝试更正确、更有效的方法。

ojsjcaue

ojsjcaue1#

过滤表中的age >= 18并聚集:

SELECT id,
       last_name,
       first_name,
       MIN(age) AS age
FROM people
WHERE age >= 18
GROUP BY last_name;

SQLite从每个组中挑选具有最小年龄的行。
参见demo

x759pob2

x759pob22#

标准SQL中的典型方法是对行进行排序:

SELECT id, last_name, first_name, age
FROM
(
  SELECT
    id,
    last_name,
    first_name,
    age,
    ROW_NUMBER() OVER (PARTITION BY last_name ORDER BY age) AS rn
  FROM people p
  WHERE age >= 18
) ranked
WHERE rn = 1;

或使用聚合

SELECT *
FROM people 
WHERE (last_name, age) IN
(
  SELECT
    last_name,
    MAX(age)
  FROM people p
  WHERE age >= 18
  GROUP BY last_name
);

或使用WHERE NOT EXISTS <a younger person >= 18 in the same family>)。

WITH eighteen_up AS
(
  SELECT *
  FROM people 
  WHERE age >= 18
)
SELECT *
FROM eighteen_up p
WHERE NOT EXISTS
(
  SELECT null
  FROM eighteen_up younger
  WHERE younger.last_name = p.last_name
  AND younger.age < p.age
);

在SQLite中,您通常可以得到更简单的操作,如forpas的回答所示,因为它们对裸列的特殊处理,而其他DBMS没有。它有它的限制与关系,虽然我解释如下。因此,这不是一个安全的选择。

更新

在请求评论中,你说如果有两个(或更多)最年轻的18岁以上的家庭成员(想想双胞胎),你只想选择其中一个。我的第一个查询就是这样做的(您必须使用RANKDENSE_RANK而不是ROW_NUMBER来获得这两个查询)。我的第二个查询并不像预期的那样工作,因为它会得到两个人。我的第三个查询也选择了这两个查询,但是可以通过将AND younger.age < p.age替换为AND (younger.age < p.age OR (younger.age = p.age AND younger.id < p.id)),调整为只选择一个。
forpas的答案中显示的SQLite-only查询不能保证工作,因为它可以从不同的行中选择ID和名字。srinivas st的查询作为我的第二个查询,即。也会选择两行。
结论:在可能出现关系的情况下,唯一不应该使用的方法就是裸列方法。根据如何处理关系,选择任何替代方案。

vjrehmav

vjrehmav3#

我认为这个查询可以帮助你得到你想要的结果

SELECT t1.Id, t1.Last_Name, t1.First_Name, t1.Age
FROM family t1
JOIN (
    SELECT Last_Name, MIN(Age) AS MinAge
    FROM family
    WHERE Age >= 18
    GROUP BY Last_Name
) t2 ON t1.Last_Name = t2.Last_Name AND t1.Age = t2.MinAge
WHERE t1.Age >= 18;

相关问题