Как вернуть связи из функций агрегирования в SQLite - PullRequest
1 голос
/ 11 октября 2019

У меня есть вопрос с домашним заданием, который требует от меня вернуть имя старшего ребенка человека, а в случае связей вернуть все связи.

Схема для базы данных:

create table persons (
  fname     char(12),
  lname     char(12),
  bdate     date,
  bplace    char(20), 
  address   char(30),
  phone     char(12),
  primary key (fname, lname)
);
create table births (
  regno     int,
  fname     char(12),
  lname     char(12),
  regdate   date,
  regplace  char(20),
  gender    char(1),
  f_fname   char(12),
  f_lname   char(12),
  m_fname   char(12),
  m_lname   char(12),
  primary key (regno),
  foreign key (fname,lname) references persons,
  foreign key (f_fname,f_lname) references persons,
  foreign key (m_fname,m_lname) references persons
);

Мой текущий запрос


SELECT fname, lname, min(bdate)
from (SELECT *
    from persons
    JOIN births using (fname, lname)
    WHERE f_fname='Michael' and f_lname='Fox');

Где Майкл Фокс - это лицо, о котором идет речь. Ожидаемый результат -

Q4|MFOld
Q4|MFOld2

, но я могу получить только первого старшего ребенка. Я попытался использовать оператор With, но нам не разрешено использовать представления или временные таблицы для ответа на этот вопрос. Я также изучал использование Rank (), но, насколько мне известно, это было введено в insqlite v3.25, но этот вопрос будет проверен с использованием v3.11. Любое понимание того, как эти связи могут быть возвращены?

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Вы можете использовать RANK():

SELECT fname, lname, bdate
FROM (
    SELECT 
        b.fname, 
        b.lname,
        p.bdate, 
        RANK() OVER(ORDER BY bdate) rnk
    from persons p
    JOIN births b using (fname, lname)
    WHERE b.f_fname='Michael' and b.f_lname='Fox'
) x
WHERE rnk = 1;

Если вам когда-либо понадобится удалить предложение where, чтобы получить самого старшего ребенка (детей) для каждого человека, то вам нужно будет добавить использованиеa PARTITION:

SELECT fname, lname, bdate
FROM (
    SELECT 
        b.fname, 
        b.lname,
        p.bdate, 
        RANK() OVER(PARTITION BY b.f_fname, b.f_lname ORDER BY bdate) rnk
    from persons p
    JOIN births b using (fname, lname)
) x
WHERE rnk = 1;

В SQLite <3.25, где оконные функции, такие как <code>RANK(), недоступны, вы можете использовать общее табличное выражение (доступно с версии 3.8) для извлечениявсех детей Майкла Фокса и используйте NOT EXISTS для фильтрации по самым старым (и):

WITH cte AS (
    SELECT b.fname, b.lname, p.bdate
    FROM persons p
    JOIN births b using (fname, lname)
    WHERE b.f_fname = 'Michael' AND b.f_lname = 'Fox'
)
SELECT *
FROM cte c
WHERE NOT EXISTS (
    SELECT 1 FROM cte c1 WHERE c1.bdate < c.bdate
)
0 голосов
/ 11 октября 2019

Зачем вам нужно min, оно будет одинаковым для всех строк, поскольку нет группы, просто замените ее на обычную дату

   SELECT fname, lname, b_date, 
   row_number() over (partition by b_date 
    order by fname, lname) 
   from (SELECT *
  from persons
 JOIN births using (fname, lname)
 WHERE f_fname='Michael' and 
  f_lname='Fox');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...