Разминка для ума и ее решение

Представляем необязательную задачу для участников базового и продвинутого курсов.

В первую очередь это задача предназначена для тех, кто идет в ногу с план-графиком, а во вторую для всех желающих :)

К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте — залогиньтесь.

Если не активировали токен — посмотрите видео-инструкцию (видео N5)

Если вы залогинены, у Вас активирован токен доступа, но вы все равно видите эту запись — напишите нам на e-mail поддержки.

комментариев 37 на “Разминка для ума и ее решение”

  1. А я вот так делал:
    ВЫБРАТЬ
        ВЫРАЗИТЬ(РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, МЕСЯЦ) / 12 – 0.5 КАК ЧИСЛО(2, 0)) КАК ЦелыхЛет
    Единственное, меня смутило что в первом примере даты были указаны наоборот: сначала бОльшая дата, потом меньшая.

    • Да, это правильное решение.
      А вот в задании ошибка, спасибо за информацию.

  2. Майор 13.09.2011 в 17:29

    Всем доброго времени суток!
    Первый вариант который пришёл в голову – ВЫРАЗИТЬ + РАЗНОСТЬДАТ оказался на проверку не рабочим, поэтому пришлось идти по другому пути:
    <code>
    ВЫБРАТЬ
        ВЫБОР
            КОГДА ГОД(&ДатаОкончания) – ГОД(&ДатаНачала) >= 0
                    И МЕСЯЦ(&ДатаОкончания) – МЕСЯЦ(&ДатаНачала) >= 0
                    И ДЕНЬ(&ДатаОкончания) – ДЕНЬ(&ДатаНачала) >= 0
                ТОГДА ГОД(&ДатаОкончания) – ГОД(&ДатаНачала)
            ИНАЧЕ ВЫБОР
                    КОГДА ГОД(&ДатаОкончания) – ГОД(&ДатаНачала) – 1 > 0
                        ТОГДА ГОД(&ДатаОкончания) – ГОД(&ДатаНачала) – 1
                    ИНАЧЕ 0
                КОНЕЦ
        КОНЕЦ КАК ПолныхЛет
    </code>
    Примеры из задания отработали как и положено, ответ для 1.01 и 31.12 одного года даёт соответственно – 0, а вот для 1.01 следующего года уже будет 1.

  3. Андрей Кусанов 13.09.2011 в 08:47

    Идея – как с днем рождения. Разность номеров года дат дает либо верный результат, либо на один больше (ДР еще не настал!)
    Прибавляя к нач. дате это число лет, проверяем, не меньше ли получ.дата даты конца. Вычитаем год, если это так.
    “ВЫБРАТЬ
    ВЫБОР
    КОГДА &ДатаНач = ДАТАВРЕМЯ(1, 1, 1)
    ИЛИ &ДатаКон = ДАТАВРЕМЯ(1, 1, 1)
    ИЛИ &ДатаНач > &ДатаКон
    ТОГДА “Невозможно рассчитать”
    ИНАЧЕ ВЫБОР
    КОГДА &ДатаКон < ДОБАВИТЬКДАТЕ(&ДатаНач, ГОД, ГОД(&ДатаКон) – ГОД(&ДатаНач))
    ТОГДА ГОД(&ДатаКон) – ГОД(&ДатаНач) – 1
    ИНАЧЕ ГОД(&ДатаКон) – ГОД(&ДатаНач)
    КОНЕЦ
     КОНЕЦ КАК ЦелыхЛет”

  4. Юрий Торговцев 13.09.2011 в 01:14

    ВЫБРАТЬ
    Цифры.Поле1 КАК Цифра
    ПОМЕСТИТЬ Цифры
    ИЗ
    (ВЫБРАТЬ
    0 КАК Поле1

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
    1

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
    2

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
    3

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
    4

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
    5

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
    6

    ОБЪЕДИНИТЬ

    ВЫБРАТЬ
    7) КАК Цифры
    ;

    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
    (Цифры.Цифра – 1) * 512 + (Цифры1.Цифра – 1) * 64 + (Цифры2.Цифра – 1) * 8 + Цифры3.Цифра КАК Число
    ПОМЕСТИТЬ Числа
    ИЗ
    Цифры КАК Цифры,
    Цифры КАК Цифры1,
    Цифры КАК Цифры2,
    Цифры КАК Цифры3
    ;

    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
    РАЗНОСТЬДАТ(&Дата2, &Дата1, день) / 365 КАК Частное
    ПОМЕСТИТЬ ДробноеЧастное
    ;

    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
    МАКСИМУМ(ЕСТЬNULL(Числа.Число, 0)) КАК ЧислоЦелыхЛет
    ИЗ
    Числа КАК Числа
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ДробноеЧастное КАК ДробноеЧастное
    ПО Числа.Число < ДробноеЧастное.Частное

  5. Кудрявцев Олег 12.09.2011 в 22:56

    ВЫБРАТЬ
     ВЫБОР
      КОГДА (ВЫРАЗИТЬ(РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ) / 12 КАК ЧИСЛО(15, 0))) – (ВЫРАЗИТЬ(РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ) / 12 КАК ЧИСЛО(15, 1))) < 0.5
      ТОГДА
    ВЫРАЗИТЬ(РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ) / 12 – 0.5 КАК ЧИСЛО(15, 0))
     ИНАЧЕ
    ВЫРАЗИТЬ(РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ) / 12 КАК ЧИСЛО(15, 0))
     КОНЕЦ КАК РАЗНИЦА

    При условии что Дата2>Дата1

    • Кудрявцев Олег 19.09.2011 в 20:14

      А мое решение верное или можно было обойтись без проверки условий?

  6. ВЫБРАТЬ
                РАЗНОСТЬДАТ(&Дата1, &Дата2, ГОД) – ВЫБОР
                             КОГДА МЕСЯЦ(&Дата2) > МЕСЯЦ(&Дата1)
                                            ТОГДА 0
                             КОГДА МЕСЯЦ(&Дата2) < МЕСЯЦ(&Дата1)
                                            ТОГДА 1
                             ИНАЧЕ ВЫБОР
                                      КОГДА ДЕНЬ(&Дата2) >= ДЕНЬ(&Дата1)
                                                     ТОГДА 0
                                      ИНАЧЕ 1
                                      КОНЕЦ
                             КОНЕЦ КАК РазностьЦелыхЛет
    Так или еще проще? :)

    • Результат получим правильный, но мой вариант будет несколько иным :)

  7. Для указанных тестовых данных запрос возвращает верные данные в консоли запросов

    select РАЗНОСТЬДАТ(&дата1, &Дата2, ГОД) – ВЫБОР
      КОГДА МЕСЯЦ(&дата2) < МЕСЯЦ(&дата1)
       ТОГДА 1
      ИНАЧЕ 0
     КОНЕЦ КАК КоличествоЦелыхЛет

    • Хороший путь.
      Попробуйте посчитать разность лет между 13.01.2010 и 10.01.2011. Должно быть 0 лет.

      • Андрей 12.09.2011 в 12:50

        а-а-а-а… Не успел запостить…

        Но я обработал и случай совпадения месяцев и дельту по датам :-)

      • Вы совершенно правы,  при одинаковом месяце надо сравнивать
        еще и порядок дней, как говорится, и на старуху бывает проруха,
        исправлять не стану, подожду Вашего решения :)

  8. Андрей 12.09.2011 в 09:45

    Предлагаю так :-)

    ВЫБРАТЬ
     ВЫРАЗИТЬ(РАЗНОСТЬДАТ(&Дата1, &Дата2, ДЕНЬ) / 365 КАК ЧИСЛО(8, 0)) КАК РазностьДат

    • Кажется, что не будет работать.
      Если делитель будет 200, то результат будет 1. А на самом деле 200 дней это 0 целых лет..

      • Андрей 12.09.2011 в 10:45

        Так у меня делитель 365 дней – и я проверял, работает и результат возращает правильный…

        Если нужно учесть “высокостность”, то тут нужно уточнить условие по какому году (или году первой даты или году второй даты) нужно считать дни года (хотя 365 дней это общепринятый стандрт и именно он используется например в типовых расчетах среднего)

        • Андрей 12.09.2011 в 10:49

          Ой.. сори.. нужно тогда так :-)

          ВЫБРАТЬ
           ВЫРАЗИТЬ((РАЗНОСТЬДАТ(&Дата1, &Дата2, ДЕНЬ) / 365 – 0.5) КАК ЧИСЛО(8, 0)) КАК РазностьДат

          • Андрей 12.09.2011 в 11:05

            хм-м-м.. не учёл вариант “совпадения дат”

            ВЫБРАТЬ
             ВЫРАЗИТЬ((РАЗНОСТЬДАТ(&Дата1, &Дата2, ДЕНЬ) / 365 – 0.499999) КАК ЧИСЛО(8, 0)) КАК РазностьДат

            • Вот этот вариант походит на правду.
              Однако, кажется на результат может повлиять високосные года.

              Одним словом, есть более красивое и понятно решение :)

        • Прошу прощения, имел ввиду – делимое 200.
          Сейчас проверю Ваш вариант..

          • Андрей 12.09.2011 в 12:48

            Тогда ещё вариант из серии “попроще” :-)

            ВЫБРАТЬ
             ГОД(&Дата2) – ГОД(&Дата1) – ВЫБОР
              КОГДА МЕСЯЦ(&Дата2) > МЕСЯЦ(&Дата1)
               ТОГДА 0
              ИНАЧЕ ВЫБОР
                КОГДА МЕСЯЦ(&Дата2) = МЕСЯЦ(&Дата1)
                 ТОГДА ВЫБОР
                   КОГДА ДЕНЬ(&Дата2) >= ДЕНЬ(&Дата1)
                    ТОГДА 0
                   ИНАЧЕ 1
                  КОНЕЦ
                ИНАЧЕ 1
               КОНЕЦ
             КОНЕЦ КАК ПолныхЛет

            • Такой вариант мне уже нравится :)
              Но есть вариант чуть проще (короче) :)

              • Андрей 12.09.2011 в 13:32

                Тогда вариант такой:

                ВЫБРАТЬ
                 ВЫРАЗИТЬ((ГОД(&Дата2) * 10000 + МЕСЯЦ(&Дата2) * 100 + ДЕНЬ(&Дата2) – ГОД(&Дата1) * 10000 – МЕСЯЦ(&Дата1) * 100 – ДЕНЬ(&Дата1)) / 10000 – 0.5 КАК ЧИСЛО(8, 0)) КАК ПолныхЛет

                • Очень неплохо. Подобный прием я буду использовать в решении :)

  9. Интересная задачка, на первый взгляд простая, но таящая в себе ряд подводных камней:
    1.  При разнице дат, получаемой методом РазностьДат(&ДатаНачала, &ДатаОкончания, ГОД) рассчитывает именно календарную дату, поэтому во втором примере получим 1 вместо 0.
    2. При вычислении с помощью метода РазностьДат(&ДатаНачала, &ДатаОкончания, ДЕНЬ) и приведении через ВЫРАЗИТЬ КАК ЧИСЛО (15, 0) получаем округленное значение, что противоречит условиям задания. Явных методов приведения к целому числу (аналогично функции Цел()) в языке запросов нет, поэтому пришлось “изобретать велосипед”.
    3. Если значение полученное в результате вычисления будет отрицательным (пример 1, дата начала больше даты окончания), то приведение к целому числу отрицательного числа даст неверный результат (если отрицательное число не привести к положительному заранее)
    Мое решение:
    <code>
    ВЫБРАТЬ
        РАЗНОСТЬДАТ(&ДатаНачала, &ДатаОкончания, ДЕНЬ) / 365 КАК РазницаДат
    ПОМЕСТИТЬ Разница
    ;

    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
        ВЫБОР
            КОГДА Разница.РазницаДат > 0
                ТОГДА Разница.РазницаДат
            ИНАЧЕ -Разница.РазницаДат
        КОНЕЦ КАК РазницаДат
    ПОМЕСТИТЬ ОтброситьМинус
    ИЗ
        Разница КАК Разница
    ;

    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
        ВЫБОР
            КОГДА (ВЫРАЗИТЬ(ОтброситьМинус.РазницаДат КАК ЧИСЛО(15, 0))) – ОтброситьМинус.РазницаДат < 0
                ТОГДА ВЫРАЗИТЬ(ОтброситьМинус.РазницаДат КАК ЧИСЛО(15, 0))
            ИНАЧЕ ВЫРАЗИТЬ(ОтброситьМинус.РазницаДат – 0.5 КАК ЧИСЛО(15, 0))
        КОНЕЦ КАК ЦелыхЛет
    ИЗ
        ОтброситьМинус КАК ОтброситьМинус
    </code>
    Работает во всех примерах корректно. Но есть 1 момент, который я не придумал как можно учесть: количество дней в запросе задается по умолчанию, как быть если в интервал периода попадется високосный год ?

    • А ведь високосных готов может быть несколько в этой выборке, нужно что-то придумать :)

  10. У меня получился такой вариант:
    ВЫБРАТЬ
    ВЫБОР 
    КОГДА ДЕНЬГОДА(&ДатаНач) > ДЕНЬГОДА(&ДатаКон)
    ТОГДА  РАЗНОСТЬДАТ(&ДатаНач, &ДатаКон, ГОД)-1
    ИНАЧЕ РАЗНОСТЬДАТ(&ДатаНач, &ДатаКон, ГОД)
    КОНЕЦ  КАК РазностьЦелыхЛет
    Если высокосные года еще нужно учесть, то день года для каждой даты можно вычислить примерно так:
    ВЫБОР 
    КОГДА ДЕНЬГОДА(КОНЕЦПЕРИОДА(&Дата, ГОД)) = 366 И ДЕНЬГОДА(&Дата) > 60
    ТОГДА ДЕНЬГОДА(&Дата) – 1
    ИНАЧЕ ДЕНЬГОДА(&Дата)
    КОНЕЦ
     
     

    • Очень хорошо, но сложность, как мне кажется, можно решить проще.
      Чуть позже покажу в решении.

    • Учтите, что до 28 февраля дни года совпадают всегда.
      А дальше может быть различие високосный/невисокосный.

      • Да, но там есть проверка И ДЕНЬГОДА(&Дата)>60
        29 февраля это 60-ый день в году.
        То есть получается: если год високосный и дата > 29 февраля,
        то вычитаем 1 день.
        Проще не придумала. С нетерпением жду решения :)

  11. ВЫБРАТЬ
        &Дата1,
        &Дата2,
        ВЫБОР
            КОГДА РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ) < 0
                ТОГДА -РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ) / 12
            ИНАЧЕ РАЗНОСТЬДАТ(&Дата1, &Дата2, МЕСЯЦ) / 12
        КОНЕЦ КАК КоличествоМесяцев
    ПОМЕСТИТЬ ПредварительныйРасчет
    ;

    ////////////////////////////////////////////////////////////////////////////////
    ВЫБРАТЬ
        ВЫБОР
            КОГДА (ВЫРАЗИТЬ(ПредварительныйРасчет.КоличествоМесяцев + 1 КАК ЧИСЛО(15, 0))) <= ПредварительныйРасчет.КоличествоМесяцев + 1
                ТОГДА ВЫРАЗИТЬ(ПредварительныйРасчет.КоличествоМесяцев КАК ЧИСЛО(15, 0))
            ИНАЧЕ ВЫРАЗИТЬ(ПредварительныйРасчет.КоличествоМесяцев – 1 КАК ЧИСЛО(15, 0))
        КОНЕЦ КАК ЦелыхЛет
    ИЗ
        ПредварительныйРасчет КАК ПредварительныйРасчет

    • Хорошо, но есть более простой вариант :)