18 января 2013

Задачка по палиндромы

Задачка для школьников

Палиндром -- это число, которое одинаково читается в обоих направлениях.
Наибольший палиндром, который может быть получен из произведения двух двузначных чисел, это 9009 = 90 * 91

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

В лучших традициях Oracle решим её одним оператором SQL

Решение:

select S as PALINDROME, R1, R2
from (select R1, R2, S
           , trunc (mod (S, power (10, 6)) / power (10, 5)) as N6
           , trunc (mod (S, power (10, 5)) / power (10, 4)) as N5
           , trunc (mod (S, power (10, 4)) / power (10, 3)) as N4
           , trunc (mod (S, power (10, 3)) / power (10, 2)) as N3
           , trunc (mod (S, power (10, 2)) / power (10, 1)) as N2
           , trunc (mod (S, power (10, 1)) / power (10, 0)) as N1
      from (select R1, R2, R1 * R2 as S
            from (select rownum + 99 as R1 from dual connect by level<=900)
               , (select rownum + 99 as R2 from dual connect by level<=900)
            where R1 >= R2
           )
     )
where ((S <= 99999 and N1 = N5 and N2 = N4)
    or (S >  99999 and N1 = N6 and N2 = N5 and N3 = N4))
order by 1 desc

Наибольший: 906609 = 993 * 913
Наименьший: 10201 = 101 * 101

Время выполнения запроса -- 1 секунда





Найдём также палиндромы из произведения двух четырёхзначных чисел:

select S as PALINDROME, R1, R2
from (select R1, R2, S
           , trunc (mod (S, power (10, 8)) / power (10, 7)) as N8
           , trunc (mod (S, power (10, 7)) / power (10, 6)) as N7
           , trunc (mod (S, power (10, 6)) / power (10, 5)) as N6
           , trunc (mod (S, power (10, 5)) / power (10, 4)) as N5
           , trunc (mod (S, power (10, 4)) / power (10, 3)) as N4
           , trunc (mod (S, power (10, 3)) / power (10, 2)) as N3
           , trunc (mod (S, power (10, 2)) / power (10, 1)) as N2
           , trunc (mod (S, power (10, 1)) / power (10, 0)) as N1
      from (select R1, R2, R1 * R2 as S
            from (select rownum + 999 as R1 from dual connect by level<=9000)
               , (select rownum + 999 as R2 from dual connect by level<=9000)
            where R1 >= R2
           )
     )
where ((S <= 9999999 and N1 = N7 and N2 = N6 and N3 = N5)
    or (S >  9999999 and N1 = N8 and N2 = N7 and N3 = N6 and N4 = N5))
order by 1 desc

Наибольший: 99000099 = 9999 * 9901
Наименьший: 1002001 = 1001 * 1001

Время выполнения запроса -- 2 минуты

Если бы для решения был выбран процедурный подход, то время выполнения было бы нереально большим

20 ноября 2012

Oracle Spatial. Пример 2

Проверим аналитические возможности модуля Oracle Spatial для решения маркетиновых задач.

Легенда:

Среди крупнейших сетей супермаркетов в Москве выберем две -- Пятёрочку и Седьмой континент (коллеги подсказывают, что эти две сети не похожи по формату и в реальной жизни они между собой не конкурируют, но сейчас для нас это не имеет значения -- подставив адреса магазинов других сетей мы получим реальные результаты, а это -- только пример).

Магазины этих сетей находятся в спальных районах, в окружении жилых домой.
Жителям приходится выбирать, в какой магазин идти. Скорее всего, жители пойдут в ближайший.

Но есть такие дома, которые находятся на приблизительно равном расстоянии от двух супермаркетов.
Эти жители не имеют предпочтений в выборе магазина (в нашем случае, пропустим другие детерминанты покупательского выбора), и предложив им определённые условия (скидки и пр.), можно сместить предпочтения в сторону нашего магазина.

Как мы будем их искать?
  1. Найдём пары магазинов разных сетей, расположенных на расстоянии не более 2 км друг от друга.
  2. Определим расстояние между такими парами магазинов.
  3. Нарисуем на карте окружности, с центрами в каждом магазине пары и радиусом в 2 / 3 от расстояния между магазинами пары.
  4. Пересечение окружностей будет иметь вид "мяча для регби". Дома, находящиеся внутри этой области, равноудалены от обоих магазинов. Маркетинговые усилия нужно сосредоточить на жителях именно этих домов.
  5. Определим адреса домов и напечатаем карту -- рекламные листовки нужно бросать в первую очередь в почтовые ящики этих домов. Если мы располагаем базой покупателей (адреса для выданных дисконтных карт) -- то лучшие скидки предлагаем имено таким покупателям.

Данные импортированы с сайта GisLab http://gis-lab.info/projects/osm_dump/, когда-то Александр Рындин (Oracle, http://www.oraclegis.com/blog/?p=2629) рекомендовал этот источник как открытый

Вот результат выполнения расчёта:

Жёлтый цвет -- крупные магистрали,
Чёрный -- границы Москвы,
Синие маркеры и пунктирные окружности -- отметки магазинов Седьмой континент,
Красные маркеры и окружности -- магазины сети Пятёрочка







Вот как выглядит увеличенное изображение карты:
Не надо регулировать ваши мониторы -- круги не круглые из-за того, что их MapBuilder неправильно отображает


Ещё крупнее, со всеми номерами домов


Эта карта с номерами домов -- прямое руководство к действию. Сосредотачиваем маркетинговые усилия на этих территориях.

 

13 ноября 2012

Некоторый опыт работы с Big Data

Согласно отчёту McKinsey в ближайшее время планируется рост объёма данных 40% в год, при росте затрат на IT лишь в 5% год.
http://www.mckinsey.com/~/media/McKinsey/dotcom/Insights%20and%20pubs/MGI/Research/Technology%20and%20Innovation/Big%20Data/MGI_big_data_exec_summary.ashx
(Весьма популярный документ по цитируемости в инете)

В последнее время пришлось столкнуться с задачей, которая касалась большого объёма данных. Что же с ними делать ?

Некоторые размышения:

Обычно предприятия сталкиваются с тремя видами (условно) данных (из http://www.oraclegis.com/blog/?p=2501):

  1. Традиционные корпоративные данных – включая информацию о клиента из CRM-систем, транзакционные данные из ERP, транзакции веб-магазинов, записи главной бухгалтерской книги
  2. Сгенерированные машинами данные/данные с датчиков – например, Call Detail Records (“CDR”), журналы веб-серверов, умные датчики, датчики на производстве, журналы различного оборудования, данные с биржевых систем
  3. Социальные данные – например, отзывы клиентов, сайты микро-блогов таких как Twitter, социальных сетей таких как Facebook, ВКонтакте
Я остановлюсь на втором типе из этой классификации.
Столкнувшись с данными такого типа, нужно принять решение, как их хранить.
Этот тип можно условно разделить на 2 подтипа:
а) данные, которые точно понадобятся
б) данные, о которых неизвестно, понадобятся ли они
 
Моё мнение таково:
Для типа а) -- данные обогащать.
Согласно Knowledge management -- получать информацию из данных. Обычно это возможно. Нужно всего лишь отбросить лишнее (то, в чём мы уверены, что это лишнее), а оставшиеся данные -- нормализовать и положить в реляционную структуру.
Лишнее -- может быть как по горизонтали (повторяющийся текст), так и по вертикали (строки, не несущие смысловой нагрузки).
Обогащать данные нужно для того, чтобы скормить их потом какой-либо аналитической системе либо отчётам. Никакая аналитическая система (насколько я знаю) не примет на вход текст (например, строку лога web-сервера или лога smtp). Чтобы аналитическая система поняла текстовые данные, их нужно преобразовать к реляционному виду.
Так лучше сделать это один раз и хранить нормализованные данные, чем транслировать данные каждый раз, когда выполняется отчёт. Это сэкономит и время и место.

Нормализовать -- здесь ключевой тезис. Как нормализовать -- в одном из следующих постов.
 
Ну а для типа б) -- хранить, если нужно. Это как чемодан с оторванной ручкой -- и нести неудобно, и выбросить жалко.
Но нужно постараться привести тип б) к типу а)
 
Вернусь к первой цитате:
"В ближайшее время планируется рост объёма данных 40% в год, при росте затрат на IT лишь в 5% год."
Считаю, что правильным решением в условиях роста объёма данных при недостатке инвестиций будет максимизировать фондооотдачу от ИТ (от средств хранения и обработки данных).
Я применяю термин "фондоотдача", хотя в ИТ укрепился термин ROI. Термин "фондоотдача" мне импонирует тем, что допускает качественную оценку, в то время, как ROI -- необходимо считать по формуле.
Формула, в общем то, проста -- прибыль к затратам с дисконтированием -- но затраты посчитать можно, а вот прибыль в ИТ -- затруднительно.
Поэтому нужно искать существующие резервы в уже внедрённом софте, и реализовывать их --  такие резервы обычно находятся, если их как следует поискать. Реализовав резервы фондоотдача определённо возрастает, а вот ROI уже не имеет значения, после того, как первичный проект по внедрению был принят к реализации и реализован.
 

01 августа 2012

Как сослаться на PARTITION в операторе DML через переменную ? Способы

Задача: Указать название partition в виде переменной в операторе DML. Например

update INVENT_ITEMS partititon (p_Partition_Name) set QUANTITY = 0;

Я столкнулся с этим, когда мне в хранимую процедуру для апдейта партиционированной таблицы имя раздела поступало в виде строки через Advanced Queing (AQ).

Что показал анализ: штатными средствами указать название partition в виде переменной невозможно. Дискуссия была на сайте Тома Кайта, ссылка внизу.

Решение:
  1. Использовать DATAOBJ_TO_PARTITION (функция из Data Cartridge), на мой взгляд -- предпочтительный вариант. Я стараюсь использовать его. Я проверил этот вариант для всех пяти типов партиционирования HEAP-таблиц -- работает везде.
  2. Определить границы partition по ALL_TAB_PARTITIONS.HIGH_VALUE и построить фразу WHERE (тоже вариант)
  3. Использовать динамический SQL (но он обычно хуже оптимизируется)
  4. Использовать CASE (если количество partition ограничено и невелико)
Убедимся, что указание названия partition в виде переменной не работает

Создадим таблицу, строки можно не добавлять

SYS@ORTE> create table T (N number) partition by hash (N) (partition P1, partition P2, partition P3, partition P4);
Table created.

Обычный update для одной partition работает:
SYS@ORTE> update T partition (P1) set N = N + 1;
0 rows updated.

Укажем название строки в виде литерала -- не работает
SYS@ORTE> update T partition ('P1') set N = N + 1;


update T partition ('P1') set N = N + 1
                   *
ERROR at line 1:
ORA-00971: missing SET keyword

Укажем название строки в виде переменной -- не работает
SYS@ORTE> var PARTNAME varchar2(8);
SYS@ORTE> exec :PARTNAME := 'P1';
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
SYS@ORTE> print :PARTNAME
PARTNAME

--------------------------------
P1

SYS@ORTE> update T partition (:PARTNAME) set N = N + 1;
update T partition (:PARTNAME) set N = N + 1

                    *
ERROR at line 1:
ORA-14108: illegal partition-extended table name syntax
Elapsed: 00:00:00.02
В коде PL/SQL ошибка будет точно такая-же.

Решение с помощью DATAOBJ_TO_PARTITION (я выполняю в SQLPLUS, но в PL/SQL тоже будет работать).

Определим ID сегмента данных partition P1;
SYS@ORTE> select DATA_OBJECT_ID from ALL_OBJECTS where OWNER = 'SYS' and OBJECT_NAME = 'T' and SUBOBJECT_NAME = 'P1';
DATA_OBJECT_ID
--------------
         77140
Elapsed: 00:00:00.09

Создадим связываемую переменную и сошлёмся на partition через ID сегмента.
SYS@ORTE> var PART_SEG_ID number;

SYS@ORTE> exec :PART_SEG_ID := 77140
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00

SYS@ORTE> update T partition (DATAOBJ_TO_PARTITION (T, :PART_SEG_ID)) set N = N + 1;
0 rows updated.
Elapsed: 00:00:00.02

Это работает. В PL/SQL будет работать тоже
Обратите внимание, что название таблицы не надо заключать в кавычки
Полная дискуссия -- здесь http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:953139476145