NULL++
92 subscribers
49 photos
16 links
Канал для тех, кто хочет развиваться как Data Analyst, Data Engineer и BI-Analyst
@HexMikhail
Download Telegram
Сегодня я хочу рассказать, а кому-то просто напомнить, о поведении NULL при вычислении логических операций. Рассмотрю эти операции на примере PostgreSQL, но логика стандартна для большинства СУБД.
Как видите, результат выполнения логической операции не всегда будет NULL.
А последний пример, когда NOT NULL в результате даёт NULL, сломал мне мозг в своё время)

@nullpp #NULL #SQL #PostgreSQL
👌2🤷‍♀1
Продолжим интересности с NULL? =) В данных выражениях, я думаю, первые пять вообще не выбиваются из обычной логики.
А вот выражение NULL IS DISTINCT FROM NULL очень интересное. В некоторых случаях имеет смысл написать строка IS DISTINCT FROM NULL или строка IS NOT DISTINCT FROM NULL, чтобы просто проверить, равно ли NULL всё значение строки, без каких-либо дополнительных проверок полей строки. А так как выражения IS всегда возвращают TRUE или FALSE и никогда NULL даже с операндом NULL они интерпретируют значение как неизвестное логическое состояние и выдают в первом случае FALSE, а во втором TRUE.

@nullpp #NULL #SQL #PostgreSQL
🤷‍♀1
Подумал и решил рассмотреть последние два примера из предыдущего поста более подробно.
Выражению a IS DISTINCT FROM b соответствует такое вот длинное выражение a <> b OR (a IS NULL) <> (b IS NULL).
Аналогично, a IS NOT DISTINCT FROM b соответствует выражению a = b OR (a IS NULL) = (b IS NULL).
Теперь если вместо a и b подставить значения NULL, то всё встанет на свои места =)
Но в каких случаях применяются данные конструкции? Вот пример использования:
SELECT * FROM Table WHERE id IS DISTINCT FROM 17;

Результаты исключают все строки, в которых id совпадает со значением 17. Чем же такой запрос будет отличаться от простого WHERE id <> 17?
Подсказка: вся разница в NULL-значениях в результате запроса.

@nullpp #NULL #SQL #PostgreSQL
🤷‍♀1🔥1
Всем привет!
Сегодня я решил арендовать простенький VPS для того, чтобы там крутились PostgreSQL и всякие Python скрипты)
Долго искал, где есть возможность буквально в пару кликов всё настроить и чтобы было недорого, и остановился на beget.com (не реклама, если что).
Хочу для начала перенести один свой учебный проект. Когда всё получится, я запилю об этом пост.

@nullpp #PostgreSQL #VPS #Python
👍7🔥1
Всем привет!
Наконец-то я занялся финальным проектом в своём обучении. Сначала создал БД и таблицы в ней для будущей выгрузки.
Написал на Python сбор данных от предоставленного API с последующей выгрузкой полученных данных в PostgreSQL.
Создал пока что первую страницу дашборда, которая должна дать общую картину состояния бизнеса, показать ключевые метрики и их динамику во времени. Это "дашборд для руководителя", который отвечает на вопрос "Как идут наши продажи в целом?"
Когда я доделаю всё, и работу оценят, я выложу исходники + ссылку на дашборд)

@nullpp #Python #PostgreSQL #Учеба
🔥9👍3
NULL++
Всем привет! Наконец-то я занялся финальным проектом в своём обучении. Сначала создал БД и таблицы в ней для будущей выгрузки. Написал на Python сбор данных от предоставленного API с последующей выгрузкой полученных данных в PostgreSQL. Создал пока что первую…
На прошлой неделе я доделал финальный проект и сдал его. Но пока что фидбэка не было)
А значит, я пока покажу вам скриншоты дашборда, как это выглядит. Я честно постарался, чтобы любое исследование по этим данным можно было провести прямо в DataLens. Такой подход, я считаю, показывает самодостаточность созданного дашборда для полноценного анализа ситуации и принятия решений.

@nullpp #Python #PostgreSQL #Учеба
🔥4
Всем привет!
Когда я делал свой дипломный проект и арендовал виртуальный сервер, при первичной настройке выполнения скриптов по расписанию, я не мог понять почему они не выполняются в нужное время.
Мне подсказали, что нужно бы проверить таймзону самого сервера - и действительно, оказалось, что она была UTC+0 вместо привычной для меня UTC+3. Это я к чему?
К тому, что у СУБД таймзона может как совпадать с сервером, так и отличаться. Да и вообще, при работе с датой-временем надо иметь в виду, что таймзоны могут повлиять на результаты не только работы, но и аналитических выводов, которые можно получить, если мы неправильно их будем интерпретировать из-за этого.
В PostgreSQL есть два основных типа для работы со временем:
- TIMESTAMP(или TIMESTAMP WITHOUT TIME ZONE) - хранит только дату и время, без привязки к часовому поясу. Это просто число, означающее "настенные часы в определённый момент". При сохранении 2023-10-25 15:30:00 база не знает, было это в Лондоне, в Москве или в Токио.
- TIMESTAMPTZ (или TIMESTAMP WITH TIME ZONE) - рекомендуемый к использованию тип. Он не хранит пояс отдельно внутри себя. Вместо этого он конвертирует переданное значение в время по UTC (Всемирное координированное время) для хранения. При извлечении данных он преобразует это UTC-время в часовой пояс текущей сессии.
Опять же многое будет зависеть от параметров как на самом сервере, так и от параметров СУБД.
Для определённой сессии можно задать таймзону так:
SET timezone = 'Europe/Moscow';

(кстати, на это нужны определённые права для учётки PostgreSQL.
И при выполнении запросов, например
SELECT doc_dt FROM ticket;

мы получим данные вида 2025-05-12 09:23:48.000 в том случае, если типом поля doc_dt является TIMESTAMP. Впрочем, такой ответ мы получили бы и не устанавливая таймзону перед этим. То есть СУБД принимает "на веру" то, что TIMESTAMP всегда в том часовом поясе, который указан в параметрах.
Мы можем преобразовать таймзону вручную при конкретном запросе (для этого не нужно особых прав):
SELECT doc_dt::TIMESTAMP AT TIME ZONE 'Europe/Moscow' FROM ticket;

В результате получим результат вида: 2025-05-12 09:23:48.000 +0300. Как видите, в самом конце будет указан часовой пояс, причём такой, какой указан в настройках. Точнее, он его просто "припишет".
С TIMESTAMPZ ситуация иначе. Смещение во времени автоматически записывается в БД. И тогда при применении AT TIME ZONE к полю TIMESTAMPZ, он наоборот преобразует в нужный временной пояс.
SET timezone = 'Europe/Moscow';
SELECT doc_dt FROM ticket;

Результат: 2025-05-12 09:23:48.000 +0300
SELECT doc_dt::TIMESTAMP AT TIME ZONE 'Europe/Moscow' FROM ticket;

Результат: 2025-05-12 09:23:48.000 +0300

Сменим таймзону:
SET timezone = 'UTC';
SELECT doc_dt FROM ticket;

Выдаст такой же результат:
2025-05-12 09:23:48.000 +0300


А вот
SELECT doc_dt::TIMESTAMP AT TIME ZONE 'Europe/Moscow' FROM ticket;

Даст нам:
2025-05-12 06:23:48.000 +0300

Как видите AT TIME ZONE - мощный оператор для явного преобразования.
Если применить к TIMESTAMPTZ, он "снимает" пояс и возвращает TIMESTAMP в указанной зоне.
Если применить к TIMESTAMP (без пояса), он "надевает" на него указанный пояс и возвращает TIMESTAMPTZ.

Что делать?
1. Храните всё в UTC. Настройте часовой пояс сервера на UTC. Это стандарт де-факто для backend-разработки и избегает путаницы.
2. Используйте тип TIMESTAMPTZ. Позволяет PostgreSQL делать всю грязную работу по конвертации.
3. Преобразование в локальное время делайте на уровне приложения. Ваше приложение лучше знает, в каком часовом поясе находится пользователь. Передавайте данные в UTC, а финальное отображение делайте на клиенте.

#SQL #PostgreSQL #timezone @nullpp
👍5🤔2
Всем привет!
Я тут немного подумал, чем бы можно было бы разнообразить контент на канале.
Как на счёт того, чтобы выкладывать некоторые задачки (и их решения) на подумать?
Например типа такого:

Задача:
Вывести информацию в какие города можно улететь из Парижа (Paris) и сколько времени это займёт?


Решение в PostgreSQL:
SELECT 
town_to,
TIMEDIFF(time_in, time_out) as flight_time
FROM
Trip
WHERE
town_from = 'Paris';


#Задача #SQL #PostgreSQL #Авиаперелеты
🔥43
Всем привет!
Сегодня будет ещё одна задачка по той же БД

Задача:
Выведите пассажиров с самым длинным ФИО. Пробелы, дефисы и точки считаются частью имени.


Решение будет в первом комменте

#Задача #SQL #PostgreSQL #Авиаперелеты
🔥3
Всем привет!
Хочу немного поговорить сегодня о функции COUNT в SQL. Данную функцию используют для подсчёта количества строк в таблице/вьюшке/результате запроса.

1. Самый простой пример использования - это подсчёт общего количества строк:
SELECT
COUNT(*)
FROM table;

Так можно посчитать все строки, включая те, которые содержат NULL.

2. Если вместо * вставить название колонки:
SELECT
COUNT(col1)
FROM table;

то запрос посчитает количество не-NULL значений.

3. Если нужно посчитать уникальные значения, то внутри нужно добавить DISTINCT:
SELECT
COUNT(DISTINCT col1)
FROM table;

Данный способ работает в PostgreSQL, в других СУБД частенько используются другие функции.

А что, если нам необходимо посчитать количество уникальных строк по двум и более параметрам?
Тут нам поможет функция CONCAT():
SELECT COUNT(DISTINCT CONCAT(col1, ' | ', col2))
FROM table;

- Иногда col1 и col2 нужно привести к формату строки.
- Обычно используют какой-то спецсимвол для соединения, чтобы случайно не пропустить что-нибудь.
Например, если взять просто CONCAT(col1, col2), то конкатенация значений ab и c будет равна конкатенации значений a и bc: abc. То есть DISTINCT решит, что это одинаковые значения.

4. А ещё можно считать количество по условиям:
SELECT 
COUNT(CASE WHEN gender = 'F' THEN 1 END) AS F,
COUNT(CASE WHEN gender = 'M' THEN 1 END) AS M
FROM project_data;

Или вот так тоже можно:
SELECT 
COUNT(*) FILTER (WHERE gender = 'F') AS F,
COUNT(*) FILTER (WHERE gender = 'M') AS M
FROM project_data;


А ещё, нужно помнить, что функция COUNT() является агрегирующей, а это значит, что если мы хотим посчиать количество в разрезе како-нибудь параметра (значений столбца), то надо не забывать про GROUP BY.
В качестве примера, посмотрим распределение покупки товаров по половому признаку:
SELECT 
product_id,
COUNT(CASE WHEN gender = 'F' THEN 1 END) AS F,
COUNT(CASE WHEN gender = 'M' THEN 1 END) AS M
FROM project_data
GROUP BY product_id ;

В результате получим такую таблицу:
product_id|f  |m  |
----------+---+---+
536| 77| 96|
7004| 81| 75|
19812| 73| 79|
47778| 74| 72|
34354| 79| 89|
4035| 80| 82|
44342| 73| 89|
...|...|...|


#SQL #PostgreSQL #агрегация #count
🔥7
Всем привет!
Давно не было постов, да... Отдыхал, думал, снова учился... В общем то и писать пока что особо не о чём.
Год заканчивался тем, что мой голос совсем пропал, болело горло и я бесконечно чихал =)
Но уже к 3му января, я уже почти вернулся в норму и сейчас чувствую себя хорошо.
Сходил всей семьёй в кино... дважды... на русские фильмы... На Чебурашку 2 (вообще гадость) и Простоквашино (так плохо, что даже хорошо, ахаха). Видели цены??? Я ваще офигел от 450 руб за билет (а их мне надо 4 штуки)... И это на утренние сеансы. А по вечерам цены доходили до 2000 за билет...
А ещё, я не принял оффер, который мне был сделан. Моя чуйка сказала "не надо", а я ей как-то доверяю =) Может и зря, конечно, время покажет.
По учёбе я доделал проект по Apache Airflow: github.com/mishandri/airflow_project
И мне уже дали отличный фидбек на него. Если вкратце, то проект генерирует даг динамически на основе Python-словаря, лежащего в S3-хранилище. Это позволяет достаточно легко изменять работу дага без фактического изменения его кода.
Да, получилось, я считаю, очень интересно. Я постарался применить всё, чему меня научили + ещё кое-что, чего не было рассказано и было изучено самостоятельно.
И приступил к изучению PL/SQL, чтобы уметь писать всякие функции, триггеры, ветвления и циклы.
А у вас было что-то интересное за эти длинные выходные?

@nullpp #SQL #PostgreSQL #Python #Airflow #истории
👍3😁2🤔2