Pull to refresh

Решаем логическую задачу для школьников на SQL

Reading time2 min
Views8.6K
Все началось с очередного скрина в группу whatsap со следующим содержанием (оригинал не на русском языке, но это не важно):

Сумма возрастов Саши, Пети и Вити 67 лет. Когда Витя был в возрасте Саши оставалось еще 3 года до рождения Пети. Какова сумма возрастов Саши и Пети?

Ясно, что задача для школьников, но после долгих часов решения задач на SQL-EX (кстати, спасибо им больше за качественные и интересные задачи) первое что приходит в голову, это:

SELECT DISTINCT r2 + r3
           FROM (SELECT rownum r1 FROM tab) r1
 CROSS JOIN (SELECT rownum r2 FROM tab) r2
 CROSS JOIN (SELECT rownum r3 FROM tab) r3
 WHERE r1 + r2 + r3 = 67 AND r1 - r2 = r3 + 3

Где tab это любая табличка с количеством строк около 100. Решение: 32, на что в группе коллега отреагировал: «А по отдельности им по сколько?». Убираем DISTINCT и меняем "+" на ","… получается 31 пара вариантов… не совсем точный ответ. Почему то захотелось ответить точно, и имея хоть какие-то доказательства на руках.

Итак. Берем всех имеющихся клиентов в подручной базе с именами из задачи и их дни рождения:

WITH t AS
 (SELECT DISTINCT upper(NAME) NAME,
                  to_date(birthdate, 'RRRRMMDD') dob
    FROM clients
   WHERE upper(NAME) IN ('САША', 'ПЕТЯ', 'ВИТЯ'))

В оригинале имена другие, понятно что в базе имена по паспорту.
Соединяем трижды и добавляя условия, что сумма возрастов Саши и Пети равна 32, когда Вите 35:

SELECT    v.dob vitya,             --дни рождения реальных Вити, Саши и Пети
               s.dob sasha,
               p.dob petya,
               add_months(v.dob, 35 * 12) data_zadachi -- Предположительная дата рождения задачи)
          FROM t v
         CROSS JOIN t s
         CROSS JOIN t p
         WHERE v.name = 'ВИТЯ'
               AND s.name = 'САША'
               AND p.name = 'ПЕТЯ'
               AND trunc((add_months(v.dob, 35 * 12) - s.dob) / 365.24) +
               trunc((add_months(v.dob, 35 * 12) - p.dob) / 365.24) = 32

но посчитать количество клиентов заранее я не подумал, и, как оказалось, очень зря. Их, конечно же, было много, а перемножая всех друг на друга, несмотря даже на некое условие, дожидаться результата можно было бы вечно. Как то нужно уменьшать количество строк, скажем оставим только однофамильцев. После добавления условия, количество возможных вариантов оказалось около полумиллиона. Так же добавились условия, что возраст не может быть отрицательным, и при датах рождения в один и тот же день была некая путаница, поэтому немного подправил точность. Но все равно результатов было много.

Уже отписался в группе, что пытался что-то доказать, но ничего не вышло. Один из коллег предложил искать только клиентов с редким отчеством. Это уже совсем не подходило под условия задачи, но подкинуло следующую мысль.

Почему бы персонажам задачи не быть братьями? Т.е. не факт, что именно братья, это мы не можем проверить, но однофамильцы с одинаковым отчеством — это запросто. Возможно таких и нет в базе, это немного спугнуло, но после добавления условия запрос все равно выдавал 13000 возможных вариантов.

Понимая, что трачу время на всякую бесполезную ерунду, прежде чем все бросить, все-таки решил проверить фамилии и отчества. И вот оно, с фамилиями проблем нет, а вот вместо отчества на нескончаемых страницах выборки были прочерки. Т.е. запрос в основном оставил только тех клиентов, отчества которых не были известны. Простым добавлением последнего условия, получил всего 3 записи. Этот скрин со словами «вряд ли задача была сформулирована в 50-ых, а если оставить только 2001 год, то Братьям было 35, 3, 29»

Конечно же все это очень условно и ради шутки, не обязательно воспринимать все всерьез. Развлекаемся как можем, мы же программисты…
Tags:
Hubs:
Total votes 12: ↑11 and ↓1+10
Comments5

Articles