Комментарии 30
Возможно, чуть более простое решение бонусного задания:
Case можно и в запрос вставить, но Постгрес с этим, к счастью, сам справляется.
CREATE FUNCTION invert_char(s text) RETURNS text AS $$
SELECT CASE WHEN s ~ '[[:upper:]]' THEN lower(s) ELSE upper(s) END;
$$ LANGUAGE sql;
SELECT string_agg(invert_char(t),'')
FROM regexp_split_to_table(initcap('иВАнОв ИВан иВановиЧ'),'') AS t;
Case можно и в запрос вставить, но Постгрес с этим, к счастью, сам справляется.
Да, здорово!
Выходит, что в данном примере не обязательно выводить порядок для string_agg? Чтобы ничего не сдвинулось без принудительной сортировки.
Можно еще для инвертирования регистра использовать функцию translate, тогда решением бонусного задания будет:
select translate(initcap(‘иВАнОв ИВан иВанович’),’АБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯабвгдеёжзиклмнопрстуфхцчшщьыъэюя’,‘абвгдеёжзиклмнопрстуфхцчшщьыъэюяАБВГДЕЁЖЗИКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ‘) as t;
Если ограничиться русским языком, то конечно (:
Почему только русский язык?)
Так это не баг, а фича:)
Меня всегда умиляли подобные подходы к решению
На какие только велосипеды можно не пойти, когда не важно КАК, если главное сейчас и верить что это одноразово
Вот это гениально даже!
Так это не баг, а фича:)
Меня всегда умиляли подобные подходы к решению
На какие только велосипеды можно не пойти, когда не важно КАК, если главное сейчас и верить что это одноразово
Вот это гениально даже!
SELECT reverse(substring(reverse('start long striiing 12345 end') for 10));
SELECT replace(replace(replace('s p a c e', ' ', '<>'), '><', ''), '<>', ' ');
Case можно и в запрос вставить, но Постгрес с этим, к счастью, сам справляется.
Еще немного добавлю
В этой фразе заложен смысл, который не каждый поймет.
О том что в план запроса, вызвавший функцию, будет встроен текст запроса из нее
Как будто мы сами прописали этот CASE в запросе, с меньшими накладными расходами, чем «настоящий» вызов функции
Еще вариант решения бонусного задания
select
array_to_string(array_agg(substring(a from 1 for 1) || upper(substring(a from 2))), ' ')
from
(select unnest(string_to_array(lower('иВАнОв ИВан иВановиЧ'), ' ')) as a) t
1.1 Любой начинающий программист, думаю, когда первый раз столкнулся с явлением разной обработки чисел с плавающей точкой, в зависимости от микросхемы сопроцессора на его материнке, сломал себе моСк, пока не вычитал, или математически не увидел проблему чисел на разных ПК :) Я столкнулся в басике еще, когда начинал писать, дошел до решения сам, просто сравнив простой пример арифметический на двух разных ПК и увидел что числа разные — тогда и вычитал в фидо каком-то что по разному сопроцессоры работают. С тех пор, все условия равенства только нечеткие и обязательное округление, с указанием точных свойств поведения при округлении чисел с плавающей точкой.
В MySQL и SQL Server нет такой х**ни как целый числа в операциях, поэтому SELECT 3/2 выдает как положено 1.5. Если в Postgre это не так — в голову гвоздь забить разрабу, который это придумал.
2.3 NOW() на сколько я знаю, во ВСЕХ языках возвращает не дату, а дату и время. Дату всегда возвращает функция с текстом DATE в названии (в MySQL это CURDATE()). У любой функции в любом языке есть значение инкремента по умолчанию — для CURDATE это 1 день. Поэтому, запрос следующего дня всегда будет SELECT CAST(CURDATE() + 1 AS DATE) без всяких указаний интервалов и прочей чепушины.
Да, вообще вся ваша статья какие-то надуманные грабли и костыли, которых нет в нормальных языках. Просто лень уже стало писать опровержения на каждый ваш пункт — просто пшите на правильных языках и инструментах, и тогда не придется выдумывать себе проблемы на свою… голову.
В MySQL и SQL Server нет такой х**ни как целый числа в операциях, поэтому SELECT 3/2 выдает как положено 1.5. Если в Postgre это не так — в голову гвоздь забить разрабу, который это придумал.
2.3 NOW() на сколько я знаю, во ВСЕХ языках возвращает не дату, а дату и время. Дату всегда возвращает функция с текстом DATE в названии (в MySQL это CURDATE()). У любой функции в любом языке есть значение инкремента по умолчанию — для CURDATE это 1 день. Поэтому, запрос следующего дня всегда будет SELECT CAST(CURDATE() + 1 AS DATE) без всяких указаний интервалов и прочей чепушины.
Да, вообще вся ваша статья какие-то надуманные грабли и костыли, которых нет в нормальных языках. Просто лень уже стало писать опровержения на каждый ваш пункт — просто пшите на правильных языках и инструментах, и тогда не придется выдумывать себе проблемы на свою… голову.
Завтрашний день можно посчитать и как
SELECT current_date + 1
. Другое дело, что в Постгресе это смотрится как кривоватое исключение, сделанное совместимости ради. Интервалы гораздо приятнее, на самом деле.Что значит «писать на правильных языках?»
Приобрести MS SQL из-за “select 3/2” = 1.5?
Приобрести MS SQL из-за “select 3/2” = 1.5?
Ну да, ну да, по этому столько крупных компаний использует Postgres.
Какие же еще опровержения вы собрались писать?
1.1 Я как пользователь не причем, что PostrgeSQL так работает. Но показываю это, чтобы осветить нюанс.
2.2 Хочу напомнить, что статья не называется «Делай так, как я показываю», а рассчитана на обучение.
Иначе, я бы писал «показать текущую дату можно так „SELECT current_date“, как вы. Это строка, из которой ничего не выжать (кроме current_time, об этом ниже)
Видимо не все понимают посыл статьи, и готовы цепляться за ерунду.
Я не поленюсь пояснить.
На мой взгляд, чтобы обучаться SQL, надо выполнять запросы и „играться“ с ними.
Мой пример прост для понимания и дает место для фантазии.
Поясню, как бы я его воспринимал, если бы никогда не работал с датами, но желал бы немного разобраться.
Я бы задался вопросом „А что будет, если?“:
И, вдохновившись какими-то результатами, отправлюсь читать MANUAL, т.к. там все темы подробно раскрыты…
Еще мне писали:
Все для того, же… Это просто задача, как в школе о покупке 10 арбузов…
Я сам долго ленился учить регулярки, пока не понял, что все достаточно просто.
1.1 Я как пользователь не причем, что PostrgeSQL так работает. Но показываю это, чтобы осветить нюанс.
2.2 Хочу напомнить, что статья не называется «Делай так, как я показываю», а рассчитана на обучение.
Иначе, я бы писал «показать текущую дату можно так „SELECT current_date“, как вы. Это строка, из которой ничего не выжать (кроме current_time, об этом ниже)
Видимо не все понимают посыл статьи, и готовы цепляться за ерунду.
Я не поленюсь пояснить.
На мой взгляд, чтобы обучаться SQL, надо выполнять запросы и „играться“ с ними.
Мой пример прост для понимания и дает место для фантазии.
SELECT CAST((now()+ INTERVAL '1 DAY') AS DATE)
Поясню, как бы я его воспринимал, если бы никогда не работал с датами, но желал бы немного разобраться.
Я бы задался вопросом „А что будет, если?“:
- заменю DAY на (week, month, year и т.д.)
- заменю +1 на -9000
- заменю DATE на TIME
- уберу CAST
- оставлю только NOW()
и т.д.
И, вдохновившись какими-то результатами, отправлюсь читать MANUAL, т.к. там все темы подробно раскрыты…
Еще мне писали:
"Не представляю, для чего может пригодиться считать количество ЗАГЛАВНЫХ (английских) букв?"
Все для того, же… Это просто задача, как в школе о покупке 10 арбузов…
Я сам долго ленился учить регулярки, пока не понял, что все достаточно просто.
Потрясающе!) думаю с этого надо было начать пост! с того как подходить к Вашим примерам.
Спасибо за статью! работаю с PostgreSQL давно, и для опытного DWH само собой ничего нового, но я бы гораздо быстрее освоился в начале карьеры, будь тогда такой материал.
Спасибо за статью! работаю с PostgreSQL давно, и для опытного DWH само собой ничего нового, но я бы гораздо быстрее освоился в начале карьеры, будь тогда такой материал.
Заголовок спойлера
Даже зарегистрироваля ради того, чтоб лайк поставить, но нельзя(
В MySQL и SQL Server нет такой х**ни как целый числа в операциях, поэтому SELECT 3/2 выдает как положено 1.5. Если в Postgre это не так — в голову гвоздь забить разрабу, который это придумал.
Это ложь.
Select 3/2 в MSSqlserver вернет 1.
С чего бы возвращать что-то еще, если оба операнда — целочисленные?
2.3 NOW() на сколько я знаю, во ВСЕХ языках возвращает не дату, а дату и время. Дату всегда возвращает функция с текстом DATE в названии (в MySQL это CURDATE()). У любой функции в любом языке есть значение инкремента по умолчанию — для CURDATE это 1 день. Поэтому, запрос следующего дня всегда будет SELECT CAST(CURDATE() + 1 AS DATE) без всяких указаний интервалов и прочей чепушины.
Не нужно говорить за всех.
Для MSSQLSERVER это будет звучать как:
Select dateadd(day, 1, cast(CURRENTTIMESTAMP AS DATE))
На счет MS SQL — вы правы, просто у меня в настройках стоит коррекция формата SQL, и этот запрос выполняется в моем MS SQL как надо, и возвращает дробь (по дефолту со стандартом мелкомягких — там такой же трабл). Что еще раз говорит о том, что нужно использовать правильный софт и инструменты (или до-настраивать бажные, чтобы не получать такое вот чудо арифметики).
На счет даты — в MSSQL инкрементом дневной даты обладает GETDATE(), так, что её можно использовать без суффиксов (но она плохо оптимизируется, вроде, как).
Вообще, мелокмягкие со своими стандартами SQL, меня достали еще в детстве, в своем косом MSAccess. Я тогда уже их люто невзлюбил за реализацию SQL запросов. И они десятилетяими так и продолжают топтать грабли своих косых разработчиков (впрочем, как и с их IE это у них, наверное какой-то культ там).
На счет даты — в MSSQL инкрементом дневной даты обладает GETDATE(), так, что её можно использовать без суффиксов (но она плохо оптимизируется, вроде, как).
Вообще, мелокмягкие со своими стандартами SQL, меня достали еще в детстве, в своем косом MSAccess. Я тогда уже их люто невзлюбил за реализацию SQL запросов. И они десятилетяими так и продолжают топтать грабли своих косых разработчиков (впрочем, как и с их IE это у них, наверное какой-то культ там).
На счет MS SQL — вы правы, просто у меня в настройках стоит коррекция формата SQL, и этот запрос выполняется в моем MS SQL как надо, и возвращает дробь (по дефолту со стандартом мелкомягких — там такой же трабл). Что еще раз говорит о том, что нужно использовать правильный софт и инструменты (или до-настраивать бажные, чтобы не получать такое вот чудо арифметики).
На счет даты — в MSSQL инкрементом дневной даты обладает GETDATE(), так, что её можно использовать без суффиксов (но она плохо оптимизируется, вроде, как).
Вообще, мелокмягкие со своими стандартами SQL, меня достали еще в детстве, в своем косом MSAccess. Я тогда уже их люто невзлюбил за реализацию SQL запросов. И они десятилетяими так и продолжают топтать грабли своих косых разработчиков (впрочем, как и с их IE это у них, наверное какой-то культ там).
При этом, в том же VB6, который тоже писали ребята из мелкомягких, целочисленное деление, если оно вдруг понадобилось программисту, было реализовано как положено во всех нормальных языках — обратным слэшем \, чтобы явно отличаться от общей операции деления по всем арифметическим правилам. Вот и пойми их там в долине, кто в каком культе состоял и продолжает состоять по сей день.
На счет даты — в MSSQL инкрементом дневной даты обладает GETDATE(), так, что её можно использовать без суффиксов (но она плохо оптимизируется, вроде, как).
Вообще, мелокмягкие со своими стандартами SQL, меня достали еще в детстве, в своем косом MSAccess. Я тогда уже их люто невзлюбил за реализацию SQL запросов. И они десятилетяими так и продолжают топтать грабли своих косых разработчиков (впрочем, как и с их IE это у них, наверное какой-то культ там).
При этом, в том же VB6, который тоже писали ребята из мелкомягких, целочисленное деление, если оно вдруг понадобилось программисту, было реализовано как положено во всех нормальных языках — обратным слэшем \, чтобы явно отличаться от общей операции деления по всем арифметическим правилам. Вот и пойми их там в долине, кто в каком культе состоял и продолжает состоять по сей день.
Нет, ничем подобным GETDATE() — не обладает.
docs.microsoft.com/ru-ru/sql/t-sql/functions/getdate-transact-sql?view=sql-server-2017
Вообще, в MSSQLSERVER — все манипуляции с датой и временем — только через функции даты и времени.
Нет, застарелые олдфаги еще помнят, что datetime можно привести к float, и что-то там делать, например — округлить:
SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME)
Но тем, кто помоложе, гадостям учиться не надо. Не окупается.
docs.microsoft.com/ru-ru/sql/t-sql/functions/getdate-transact-sql?view=sql-server-2017
Вообще, в MSSQLSERVER — все манипуляции с датой и временем — только через функции даты и времени.
Нет, застарелые олдфаги еще помнят, что datetime можно привести к float, и что-то там делать, например — округлить:
SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) AS DATETIME)
Но тем, кто помоложе, гадостям учиться не надо. Не окупается.
Спасибо! Пинок и правда есть, но достаточно нейтральный, чтобы не опустить руки :)
Насколько Вам кажется, что нужна теория по устройству СУБД, чтобы писать нормальные запросы?
Насколько Вам кажется, что нужна теория по устройству СУБД, чтобы писать нормальные запросы?
Замечательная статья, пришлось поломать голову над некоторыми вопросами. Бонусные задания решил иначе. Автор, скажите, а когда появится новая публикация в таком же стиле, как и эта? Хочется чего-то вроде и серьёзного, но с другой стороны и веселого.
Спасибо за публикацию. По задаче 2.1 помнил, что есть особенности с NULL. Пришлось перечитать документацию. Пиши ещё.
Немного другая версия задачи 13 от пользователя kirill_petrov на особенность READ COMMITTED
Какие значения окажутся в таблице?
-- Имеется таблица с двумя строками
CREATE TABLE goods (discount) AS
(SELECT 10::INT
UNION ALL
SELECT 15);
-- 1. User_1 выполняет запрос (транзакция остается открыта):
BEGIN;
UPDATE goods
SET discount = discount + 5;
--2. User_2 выполняет запрос:
UPDATE goods
SET discount = discount + 100
WHERE discount = 15
--3. User_1 выполняет
COMMIT;
Какие значения окажутся в таблице?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Задачи и решения для бойца PostgreSQL