Дано: сбор статистики уровня смертности по районам/датам/диагнозам. Дата задана столбцом типа timestamp.
База - postgres. Реализация OLAP - Pentaho Mondrian 9.0.0.0-SNAPSHOT с гитхаба.
Нужно разделение даты на годы/месяцы/дни. Мондриан не хочет привязываться к одной колонке, требует для каждого уровня иерархии отдельную колонку. Окей, создал вьюху, с ключом date (timestamp), столбцы year, month, day (числовые).
Как с такими входными данными задать интервал с произвольными датами? Например, с 2018-02-15 до 2018-03-04. Гугл выдаёт кучу разных вариантов с двоеточиями и знаками вопроса (типа [?20180215] : [2018.03.04]). Ни один из них не заработал. Возможно, оттого, что я накосячил с выбором столбцов для уровней, возможно, из-за капризности мондриана (о ней - чуть дальше).
Окей, создаём в иерархии даты уровень "AllDate", ссылающийся на колонку date. Пытаюсь сравнить даты напрямую.
Оказывается, что две даты напрямую сравнивать нельзя. Ну кто бы мог подумать.
Так, есть функция datediff, попробуем её.
И получаем подляну от функции CDATE, потому что она не понимает формата yyyy-MM-dd.
Идём гуглить суть проблемы:
То есть это капризное говно понимает только один формат, зависящий от текущей локали.
Реализацию этого говна, к сожалению, так и не нашёл, хотя все исходники на руках, так что убедиться лично не удалось.
Ладно, тратим ещё полдня, чтобы разобраться, как писать собственные функции, и пишем свою функцию GetData, которая конвертирует строку в DateTime по заданному формату.
И получаем былинный отказ уже от постгреса. Оказывается, этот mdx-запрос превращается в sql-запрос, в котором столбец даты сравнивается со столбцом даты, а для сравнения на оба операнда наворачивается функция UPPER(), как будто об этом кто-то просил, а функции UPPER с операндом типа timestamp, естественно, не существует.
Окей, наворачиваем нашу функцию GetData и на первый операнд.
Теперь ломается GetDate, потому что [Date.YMDHierarchy].[AllDate].CurrentMember.VALUE внезапно почему-то выдаёт numeric.
Для диагностики меняю тип входного аргумента у GetDate, и в отладке выясняю, что [Date.YMDHierarchy].[AllDate].CurrentMember.VALUE выдаёт дабловское значение "0.0".
Может, в типе дело?
Правлю вьюху в базе, через cast(as character varying) переделываю столбцу date тип с timestamp на string. Проверяю - в столбце значения вида "2017-08-29 14:42:00". Тут всё окей. Правлю схему, добавляю новое измерение (StandardDimension вместо TimeDimension), новую иерархию, только один уровень "AllDate" типа String. В Schema Workbench схема компилится. Правда, в Saiku Analytics почему-то не добавляется.
Правлю запрос в своей джава-программе:
Теперь я точно уверен, что в AllDate стринг. Но в GetDate на вход опять приходит "0.0". В рот мне ноги, Дэвид Блэйн, как ты это сделал?
Мне нужно дёргать что-то другое, а не CurrentMember и не CurrentMember.VALUE?
Подскажите, или как сделать эту фигню нормально, или в каком именно месте я олень.
База - postgres. Реализация OLAP - Pentaho Mondrian 9.0.0.0-SNAPSHOT с гитхаба.
Нужно разделение даты на годы/месяцы/дни. Мондриан не хочет привязываться к одной колонке, требует для каждого уровня иерархии отдельную колонку. Окей, создал вьюху, с ключом date (timestamp), столбцы year, month, day (числовые).
Как с такими входными данными задать интервал с произвольными датами? Например, с 2018-02-15 до 2018-03-04. Гугл выдаёт кучу разных вариантов с двоеточиями и знаками вопроса (типа [?20180215] : [2018.03.04]). Ни один из них не заработал. Возможно, оттого, что я накосячил с выбором столбцов для уровней, возможно, из-за капризности мондриана (о ней - чуть дальше).
Окей, создаём в иерархии даты уровень "AllDate", ссылающийся на колонку date. Пытаюсь сравнить даты напрямую.
"SELECT\n" + "NON EMPTY {[Measures].[Death Count]} ON COLUMNS,\n" + "NON EMPTY FILTER({[Date.YMDHierarchy].[AllDate].Members},[Date.YMDHierarchy].[AllDate].CurrentMember.VALUE) >= CDATE('2018-02-15'))\n" + " ON ROWS\n" + "FROM [DeathRate]";
Оказывается, что две даты напрямую сравнивать нельзя. Ну кто бы мог подумать.
Так, есть функция datediff, попробуем её.
"NON EMPTY FILTER({[Date.YMDHierarchy].[AllDate].Members},datediff(\"d\", [Date.YMDHierarchy].[AllDate].CurrentMember.VALUE, CDATE('2018-02-15') > 0)\n"
И получаем подляну от функции CDATE, потому что она не понимает формата yyyy-MM-dd.
Идём гуглить суть проблемы:
The java code behind the CDate function, invokes DateFormat.getDateInstance without parameters, returning a new instance of SimpleDateFormat. As the style of the date isn't specified (FULL, LONG, MEDIUM or SHORT), the only accepted format is MEDIUM. The date format is also locale specific in which case we are dealing with the default one (i.e. system locale). In my case, this is en_GB. Example of date style for GB: - FULL: 16 January 2007 - LONG: 16 January 2007 - MEDIUM: 16-Jan-2007 - SHORT: 16/01/07 |
То есть это капризное говно понимает только один формат, зависящий от текущей локали.
Реализацию этого говна, к сожалению, так и не нашёл, хотя все исходники на руках, так что убедиться лично не удалось.
Ладно, тратим ещё полдня, чтобы разобраться, как писать собственные функции, и пишем свою функцию GetData, которая конвертирует строку в DateTime по заданному формату.
"NON EMPTY FILTER({[Date.YMDHierarchy].[AllDate].Members},datediff(\"d\", [Date.YMDHierarchy].[AllDate].CurrentMember.VALUE, GetDate('2018-02-15', 'yyyy-MM-dd')) > 0)\n"
И получаем былинный отказ уже от постгреса. Оказывается, этот mdx-запрос превращается в sql-запрос, в котором столбец даты сравнивается со столбцом даты, а для сравнения на оба операнда наворачивается функция UPPER(), как будто об этом кто-то просил, а функции UPPER с операндом типа timestamp, естественно, не существует.
Окей, наворачиваем нашу функцию GetData и на первый операнд.
"NON EMPTY FILTER({[Date.YMDHierarchy].[AllDate].Members},datediff(\"d\", GetDate([Date.YMDHierarchy].[AllDate].CurrentMember.VALUE, 'yyyy-MM-dd'), GetDate('2018-02-15', 'yyyy-MM-dd')) > 0)\n"
Теперь ломается GetDate, потому что [Date.YMDHierarchy].[AllDate].CurrentMember.VALUE внезапно почему-то выдаёт numeric.
Для диагностики меняю тип входного аргумента у GetDate, и в отладке выясняю, что [Date.YMDHierarchy].[AllDate].CurrentMember.VALUE выдаёт дабловское значение "0.0".
Может, в типе дело?
Правлю вьюху в базе, через cast(as character varying) переделываю столбцу date тип с timestamp на string. Проверяю - в столбце значения вида "2017-08-29 14:42:00". Тут всё окей. Правлю схему, добавляю новое измерение (StandardDimension вместо TimeDimension), новую иерархию, только один уровень "AllDate" типа String. В Schema Workbench схема компилится. Правда, в Saiku Analytics почему-то не добавляется.
Правлю запрос в своей джава-программе:
+ "NON EMPTY FILTER({[DateString.DateStringHierarchy].[AllDate].Members},datediff(\"d\", GetDate([DateString.DateStringHierarchy].[AllDate].CurrentMember, 'yyyy-MM-dd'), GetDate('2018-02-15', 'yyyy-MM-dd')) > 0)\n"
Теперь я точно уверен, что в AllDate стринг. Но в GetDate на вход опять приходит "0.0". В рот мне ноги, Дэвид Блэйн, как ты это сделал?
Мне нужно дёргать что-то другое, а не CurrentMember и не CurrentMember.VALUE?
Подскажите, или как сделать эту фигню нормально, или в каком именно месте я олень.