Горячее
Лучшее
Свежее
Подписки
Сообщества
Блоги
Эксперты
Войти
Забыли пароль?
или продолжите с
Создать аккаунт
Регистрируясь, я даю согласие на обработку данных и условия почтовых рассылок.
или
Восстановление пароля
Восстановление пароля
Получить код в Telegram
Войти с Яндекс ID Войти через VK ID
ПромокодыРаботаКурсыРекламаИгрыПополнение Steam
Пикабу Игры +1000 бесплатных онлайн игр Возглавьте армию своей страны в войне с коварным врагом. Управляйте ресурсами, принимайте ключевые решения и ведите Граднар через суровый конфликт. Ваши действия определяют будущее, приводя страну к победе или поражению.

Симулятор войны: 1985

Мидкорные, Стратегии, Симуляторы

Играть

Топ прошлой недели

  • solenakrivetka solenakrivetka 7 постов
  • Animalrescueed Animalrescueed 53 поста
  • ia.panorama ia.panorama 12 постов
Посмотреть весь топ

Лучшие посты недели

Рассылка Пикабу: отправляем самые рейтинговые материалы за 7 дней 🔥

Нажимая «Подписаться», я даю согласие на обработку данных и условия почтовых рассылок.

Спасибо, что подписались!
Пожалуйста, проверьте почту 😊

Помощь Кодекс Пикабу Команда Пикабу Моб. приложение
Правила соцсети О рекомендациях О компании
Промокоды Биг Гик Промокоды Lamoda Промокоды МВидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
0 просмотренных постов скрыто
2
user5236465

Небольшой тренинг по XML в PostgreSQL на примере производственного календаря⁠⁠

1 месяц назад

Новый Год уже скоро, а значит нужен свежий производственный календарь в базе данных PostgreSQL. Но как совершенно обленившийся IT-шник, заводить его руками не хочется. Хочется, чтобы вызовом одной функции он сразу появился. Ну а уж из этой функции можно его сохранить в табличку и спокойно использовать до следующего Нового Года. А тогда опять просто вызвать функцию и с чистой совестью отрапортовать о выполненной работе. Моя цель - показать возможности COPY ... FROM PROGRAM и простейшие приемы парсинга XML в PostgreSQL.

Для начала пришлось поискать, где же его взять в наиболее удобном для обработки виде. Нашел!

Ставить какие-либо расширения на PostgreSQL не хотелось, поэтому ограничился прямым вызовом wget через COPY. Для этого сначала создаем временную таблицу:

DROP TABLE IF EXISTS tmp_tmp;
CREATE TEMP TABLE tmp_tmp (
  ID serial PRIMARY KEY,
  res text NOT NULL);

ID нам нужен исключительно для сохранения порядка строк, полученных от wget. Теперь мы вполне можем заполнить эту табличку и даже посмотреть на результат:

COPY tmp_tmp (res) FROM PROGRAM
  '/usr/bin/wget -qO - https://xmlcalendar.ru/data/ru/2026/calendar.xml'
  WITH (FORMAT text);
SELECT res FROM tmp_tmp ORDER BY ID;

Теперь нам нужно из полученных текстовых строк получить XML

SELECT string_agg(res,'' ORDER BY ID)::xml AS res
FROM tmp_tmp

Для проверки при помощи xmltable() распарсим заголовочную строку вида <calendar year="2026" lang="ru" date="2025.09.30" country="ru">, содержащую год, страну, для которой этот календарь, и дату его последнего изменения.

WITH CTE AS (
  SELECT string_agg(res,'' ORDER BY ID)::xml AS res
  FROM tmp_tmp ),
CheckYear AS (
  SELECT Y.for_year, Y.for_country, Y.create_date
  FROM CTE C
  CROSS JOIN xmltable('//calendar' PASSING C.res COLUMNS
    for_year smallint PATH '@year',
    for_country varchar PATH '@Country',
    create_date date PATH '@DaTe') Y
  WHERE Y.for_year=2026::smallint )
SELECT * FROM CheckYear

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

Теперь распарсим таблицу праздников. Она содержит только внутренний числовой идентификатор праздника и его полное наименование в строках вида <holiday id="6" title="День Победы"/>

WITH [...]
Holidays AS (
  SELECT H.id, H.title
  FROM CheckYear Y
  CROSS JOIN CTE C
  CROSS JOIN xmltable('//calendar/holidays/holiday' PASSING C.res COLUMNS
    id smallint PATH '@id',
    title varchar PATH '@title') H )
SELECT * FROM Holidays;

Затем распарсим основную часть, содержащую строки вида <day d="03.08" t="1" h="4"/> или <day d="04.29" t="1" f="04.27"/>. Тут требуются пояснения. Под тегом d скрывается дата в формате ММ.ДД. Тег t определяет тип записи: 1 - выходной день, 2 - рабочий и сокращенный (может быть использован для любого дня недели), 3 - рабочий день (суббота/воскресенье). Тег h является ссылкой на идентификатор праздника из предыдущего запроса. А тег f - дата с которой был перенесен выходной день тоже в формате ММ.ДД. При этом суббота и воскресенье считаются выходными, если нет тегов day с атрибутом t=2 и t=3 за этот день.

WITH [...]
SpecialDays AS (
  SELECT ('2026-'
    ||left(D.d,2)||'-'
    ||right(D.d,2))::date AS special_date,
  CASE WHEN D.t=1 THEN 'Holiday'
    WHEN D.t=2 THEN 'Shortened'
    WHEN D.t=3 THEN 'Working'
    ELSE NULL END AS day_type,
  ('2026-'
    ||left(D.f,2)||'-'
    ||right(D.f,2))::date AS from_date,
    H.title AS holiday_name
  FROM CheckYear Y
  CROSS JOIN CTE C
  CROSS JOIN xmltable('//calendar/days/day' PASSING C.res COLUMNS
    d varchar(5) PATH '@d',
    t smallint PATH '@t',
    h smallint PATH '@h',
    f varchar(5) PATH '@f') D
  LEFT JOIN Holidays H ON H.id=D.h )
SELECT * FROM SpecialDays;

Для наглядности я заменил числовые типы на краткое их строковое описание. Даты же из формата MM.ДД преобразовал в формат ISO ГГГГ-ММ-ДД, а затем уже в тип date.

Теперь осталось только сгенерировать календарь за год и для каждого дня указать количество рабочих часов для 40-часовой рабочей недели.

SELECT C.d::date AS pk_date,
  CASE WHEN S.day_type='Shortened' THEN 7
    WHEN S.day_type='Working' THEN 8
    WHEN S.day_type='Holiday' THEN 0
    WHEN extract(DOW FROM C.d) IN (0,6) THEN 0
    ELSE 8 END::smallint AS working_hours,
  S.from_date, S.holiday_name
FROM generate_series(('2026-01-01')::timestamp,
  ('2026-12-31')::timestamp,
   '1 day'::interval) C(d)
LEFT JOIN SpecialDays S ON S.special_date=C.d;

Сокращенные предпраздничные дни получили по 7 часов. Рабочие дни в выходные - 8. Праздники - 0. Воскресенье и суббота (в PostgreSQL нулевой и шестой дни недели соответственно) - 0. Ну а остальные дни считаются рабочими по 8 часов.

После всего этого осталось только создать функцию

CREATE OR REPLACE FUNCTION get_working_calendar(
  calendar_year smallint,
  calendar_lang varchar(2)='ru')
RETURNS TABLE (
  pk_date date,
  working_house smallint,
  from_date date,
  holiday_name varchar
) AS $function$
<<func>>
DECLARE
  sql_cmd varchar='COPY tmp_tmp (res) FROM PROGRAM $$'
    ||$$/usr/bin/wget -qO - https://xmlcalendar.ru/data/$$
    ||calendar_lang||$$/$$
    ||calendar_year::text
    ||$$/calendar.xml --no-check-certificate$$
    ||'$$ WITH (FORMAT text);';
BEGIN
DROP TABLE IF EXISTS tmp_tmp;
CREATE TEMP TABLE tmp_tmp (
  ID serial PRIMARY KEY,
  res text NOT NULL);
EXECUTE func.sql_cmd;

RETURN QUERY WITH CTE AS (
  SELECT string_agg(res,'' ORDER BY ID)::xml AS res
  FROM tmp_tmp ),
CheckYear AS (
  SELECT Y.for_year, Y.for_country, Y.create_date
  FROM CTE C
  CROSS JOIN xmltable('//calendar' PASSING C.res COLUMNS
    for_year smallint PATH '@year',
    for_country varchar PATH '@country,
    create_date date PATH '@date') Y
  WHERE Y.for_year=calendar_year ),
Holidays AS (
  SELECT H.id, H.title
  FROM CheckYear Y
  CROSS JOIN CTE C
  CROSS JOIN xmltable('//calendar/holidays/holiday'
    PASSING C.res COLUMNS
    id smallint PATH '@id',
    title varchar PATH '@title') H ),
SpecialDays AS (
  SELECT (calendar_year::text||'-'
    ||left(D.d,2)||'-'
    ||right(D.d,2))::date AS special_date,
  CASE WHEN D.t=1 THEN 'Holiday'
    WHEN D.t=2 THEN 'Shortened'
    WHEN D.t=3 THEN 'Working'
    ELSE NULL END AS day_type,
    (calendar_year::text||'-'
      ||left(D.f,2)||'-'
      ||right(D.f,2))::date AS from_date,
    H.title AS holiday_name
  FROM CheckYear Y
  CROSS JOIN CTE C
  CROSS JOIN xmltable('//calendar/days/day' PASSING C.res COLUMNS
    d varchar(5) PATH '@d',
    t smallint PATH '@t',
    h smallint PATH '@h',
    f varchar(5) PATH '@f') D
  LEFT JOIN Holidays H ON H.id=D.h )
SELECT C.d::date AS pk_date,
  CASE WHEN S.day_type='Shortened' THEN 7
    WHEN S.day_type='Working' THEN 8
    WHEN S.day_type='Holiday' THEN 0
    WHEN extract(DOW FROM C.d) IN (0,6) THEN 0
    ELSE 8 END::smallint AS working_hours,
  S.from_date, S.holiday_name
FROM CheckYear Y
CROSS JOIN generate_series((calendar_year::text||'-01-01')::timestamp,
    (calendar_year::text||'-12-31')::timestamp,
    '1 day'::interval) C(d)
LEFT JOIN SpecialDays S ON S.special_date=C.d;
END; $function$ LANGUAGE plpgsql;

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

SELECT * FROM get_working_calendar(2024::smallint);

P.S. Забыл указать, что доступны производственные календари с 2015 года для России (ru) Белоруссии (by), Украины (ua), Казахстана (kz) и Узбекистана (uz)

P.P.S. Простите, если что, но после совершенно убогих постов про SQL, захотелось написать пост имеющий хоть ничтожную практическую ценность.

Показать полностью
SQL Postgresql Xml Текст Длиннопост
22
Eye.Providence
Eye.Providence

Ответ на пост «Сравнение Yaml и Json»⁠⁠1

7 месяцев назад

Байтовый протокол лучше

I`m CTO bitch IT юмор Разработка Json Xml IT Мат Спор Короткопост Ответ на пост Текст
15
314
imctobitch
imctobitch
Норм автор
Серия I'm CTO, bitch

Сравнение Yaml и Json⁠⁠1

7 месяцев назад
Сравнение Yaml и Json

😡 Телеграм-канал

[моё] I`m CTO bitch IT юмор Разработка Json Xml IT Мат Спор
65
user9681637
user9681637

Почему XSLT тянут в информационные системы, ведь это инструмент подготовки полиграфической продукции?⁠⁠

1 год назад

Почему XSLT тянут в информационные системы, ведь это инструмент подготовки полиграфической продукции?

IT Xml Информационные системы Полиграфия Текст
12
7
Starkee
Starkee

XML в человекочитаемый вид⁠⁠

1 год назад

По работе создаю запросы, а ответы на них приходят в виде xml. Но не в виде файла, а просто текстом с разметкой xml. Уйма времени уходит, чтобы понять, что там написано.
Как бы это преобразовать в нормальный вид?
Гугл предлагает именно с файлом XML манипуляции производить, а у меня только текст.
Есть для такой проблемы инструменты? Желательно не онлайн

[моё] Xml Текст Файл Помощь
24
5
Dorblue666
Dorblue666

Требование опыта работы⁠⁠

2 года назад
Требование опыта работы
Опыт работы Microsoft Excel Xl Вакансии Xml Скриншот
7
257
echo0x00
echo0x00
Программисты шутят

Но я хотел блокнотом⁠⁠

3 года назад
Но я хотел блокнотом

Программисты шутят

Показать полностью 1
Картинка с текстом IT юмор Программист Xml Большая ложка Завтрак
4
DELETED

Настройка sitemap.xml / Drupal 8⁠⁠

3 года назад

Устанавливаем и включаем модуль Simple Sitemap:

composer require drupal/simple_sitemap ; drush en simple_sitemap -y

Заходим на страницы редактирования типов материалов / словарей таксономий, страницы которых должны попадать в sitemap.xml

Я захожу на страницу редактирования типа материала «Статья»:

/admin/structure/types/manage/article

В вкладке «Simple XML Sitemap» меняю радиобаттон на «Index entities of this type»

Заходим в настройки модуля «Simple Sitemap» в раздел «Пользовательские ссылки» и добавляем туда URL страниц, которые не были созданы через тип материала или таксономию. Это могут быть страницы представлений или Snippet Manager.

Страница «Статьи» у меня сделана через представление.


Сохраняем → Запускаем крон → Смотрим результат по адресу:

site.com/sitemap.xml

Если не заполнять поле «Базовый URL по умолчанию» — домен будет подставляться автоматически

Показать полностью 2
[моё] Программирование Разработка IT Drupal Backend Xml Программист SEO Cms Web Web-программирование Обучение Урок Гайд
1
Посты не найдены
О нас
О Пикабу Контакты Реклама Сообщить об ошибке Сообщить о нарушении законодательства Отзывы и предложения Новости Пикабу Мобильное приложение RSS
Информация
Помощь Кодекс Пикабу Команда Пикабу Конфиденциальность Правила соцсети О рекомендациях О компании
Наши проекты
Блоги Работа Промокоды Игры Курсы
Партнёры
Промокоды Биг Гик Промокоды Lamoda Промокоды Мвидео Промокоды Яндекс Маркет Промокоды Пятерочка Промокоды Aroma Butik Промокоды Яндекс Путешествия Промокоды Яндекс Еда Постила Футбол сегодня
На информационном ресурсе Pikabu.ru применяются рекомендательные технологии