А вот это может и не сработать, если под термином "распутывать" вы разумеете замену отрезков строго в четвёрке точек. Потому как переход между имеющейся и оптимальной конфигурацией может включать в путь конфигурацию с бОльшим количеством пересечений или бОльшей суммарной длиной отрезков.
Если мы со стороны приложения -- то можно втыкать проверки и ограничения на количества повторяемых элементов: ограничивать количество в IN (?), ограничивать количество OR/AND, ограничивать число элементов в форме, понизить максимальный размер форм
Ограничивать - это экстенсив, от которого мало толку. Логику выполнения на уровне формирования запроса нужно менять. Если встречается что-то типа AND (0=1 OR cat_id=1 OR cat_id=2 OR cat_id=3) из ~десятка (предел определяется экспериментально) или менее вариантов значения - выполняем как написано, иначе сливаем набор критериев во временную таблицу (которую ещё и проиндексировать можно). Одно дополнительное ветвление в интерактивной части кода и два разных шаблона запроса - потери минимальны, зато эффект налицо.
Разве не очевидно что такая конфигурация существует?
Увы, но я не вижу вообще никаких предпосылок к ОЧЕВИДНОСТИ такого утверждения. С вашим утверждением получается вообще ерунда, а не задача - существует ли конфигурация, которая (по вашим словам) очевидно существует.
Задача-то как раз и состоит в том, чтобы установить, всегда ли существует такая конфигурация.
Для каждого варианта посчитаем общую сумму длин всех получившихся отрезков и выберем ту конфигурацию, где эта сумма минимальна
Вполне возможна ситуация, когда конфигураций с одинаковой минимальной суммой несколько. Это касается и дальнейшего рассуждения - 4 точки могут образовывать квадрат/ромб. Придётся доказывать, что среди таких конфигураций существует та, в которой отсутствуют пересечения.
Цель - гарантировать, чтобы минимум двое ответили верно.
Правильно для текущей задачи, но некорректно для дополнения про произвольное число цветов и инопланетян. Корректная формулировка - "гарантировать не более одной ошибки".
?? Медленно и плохо - это совершенно разные вещи, медленно - далеко не всегда плохо. Иногда даже что-то приходится специально замедлять (Digger помните? ну или общеизвестное "Быстро, качественно, дёшево - выберите два из трёх"). Нет в мире совершенства, всегда приходится чем-то жертвовать, и иногда это именно скорость.
То есть рекомендуют для хранения денежных величин и тут же признают, что это весьма дорого.
А что именно тут плохо согласуется-то? По-моему, всё правильно и честно - цитаты вообще о разных вещах говорят, просто они, эти вещи, зависимы. Первая цитата предупреждает, что если нужна точность, то NUMERIC, а не FLOAT/DOUBLE, а вторая дополнительно сообщает, какова будет цена реализации этой требуемой точности.
Увы, это не всегда возможно - сделать все поля NOT NULL. Ведь в этом случае вместо NULL вам необходимо иметь некий default value, который интуитивно понятен, проходит все CHECK, не ломает FK, гарантированно не бывает в рабочем наборе, и при этом не влияет на дальнейшую обработку без добавления специфических условий типа WHERE .. AND column <> 'не определено'.
По-моему, вы меня неправильно понимаете. Я не оспариваю результат сравнения.
Я утверждаю то, что ваше пояснение в скобках ("ноль - это число") не является корректным обоснованием причины неравенства. Из вашего этого пояснения неявным образом формируется вывод, что "а NULL - это НЕ число". И вот этот вывод - он как раз и некорректен, потому что NULL в некоторых ситуациях вполне себе может иметь определённый тип данных. Как в описанном случае, когда этот тип явно определяется типом поля, так и в случае неявного определения типа, если NULL является результатом вычисления функции, и тогда тип значения определён типом возвращаемого функцией значения. В СУБД со строгой типизацией при этом можно даже схватить ошибку сравнения type mismatch, если тип возврата функции не числовой (впрочем, скорее всего эта ошибка вылезет ещё на стадии парсинга).
Вы смешиваете тип данных и значение. Да, поле имеет числовой тип, но само значение NULL не является числом в математическом смысле. Это маркер отсутствия числа в данном поле.
Я же рассматриваю вполне себе конкретную частную ситуацию. Есть конкретная таблица, в ней есть конкретное поле числового типа, есть конкретная запись, где в этом поле хранится NULL. А вы опять говорите об абстрактной ситуации. Да, определённого числового значения нет, есть NULL как маркер отсутствия значения. Но тип значения у этого маркера отсутствия в описанном случае - есть. И он будет использоваться, несмотря на отсутствие значения - например, если значение является одним из операндов функции COALESCE.
Вопрос формулировок.
Я не о формулировках, а об их смешении в одном предложении, чего настоятельно советую избегать в данном конкретном случае.
Да, это следует из определения агрегации. Если нет значений - нечего суммировать.
Но COUNT-то NULL не возвращает, а возвращает честный числовой ноль. И плевать ему, что нечего подсчитывать. Почему я и говорю, что об этом бы стоило сказать отдельно и явно - именно для начинающих.
MySQL и MariaDB реализуют ту же логику через свой собственный оператор <=>, который не является стандартным
Отож. Когда они реализовали этот оператор, никаким IS NOT DISTINCT FROM в стандарте ещё даже не пахло.
Некорректно. Если в данном случае NULL - литерал, то пояснение правильное, но если это значение поля записи числового типа, то он вполне себе число, ибо тип и значение есть разные атрибуты. Хотя он по-прежнему не равен нулю.
FALSE AND UNKNOWN = FALSE (это неинтуитивно, но так работает стандарт SQL
Да вполне себе интуитивно. Чтобы получить TRUE, нужно, чтобы все соединяемые через AND значения были TRUE.
В WHERE, CHECK условие считается истинным, только если выражение вернуло TRUE. Если вернулось FALSE или UNKNOWN — строка отклоняется / ограничение не нарушается (потому что для нарушения нужно FALSE, а не UNKNOWN).
Ну это вы сильно запутаете того, кто не в теме. Лучше распишите по отдельности, что WHERE требует TRUE, тогда как CHECK требует что угодно, лишь бы не FALSE.
SUM, AVG и COUNT(column) тихо игнорируют NULL.
Следует оговорить, что если все значения в группе есть NULL, то агрегатная функция вернёт-таки NULL. А ещё я бы добавил, что COUNT как раз NULL возвращать не умеет, что для начинающих тоже не всегда очевидно.
В PostgreSQL и свежих версиях SQL Server уже появился оператор IS [NOT] DISTINCT FROM.
Они не единственные. В MySQL/MariaDB давным-давно есть два разных оператора сравнения - обычное compare ( = ) и null-safe compare ( <=> ).
Решение: используйте NOT EXISTS:
Увы, неуниверсально. Далеко не всегда обычный подзапрос можно преобразовать в коррелированный (пусть это и нечастая ситуация). К тому же далеко не факт, что такое преобразование не скажется самым фатальным образом на плане выполнения.
Хорошо бы ещё узнать, сколько это в процентах от общего числа скончавшихся не по естественным причинам, и на каком месте в таком списке именно эта причина смертности. Возможно, выяснится, что начинать-то надо совсем даже не с авто...
Их владельцам нужно будет подать заявление на «Госуслугах» с фотографией электросамоката, после чего забрать из ГИБДД свидетельство о регистрации и номер.
Ага... и потом идентифицировать его по фотографии. Ну класс вообще. Так прямо в свидетельстве о регистрации в графе для VIN и напишем - фотография 800х600px от 01/01/2026. Или засылаем, как на фото выше, с пометкой "мой - третий слева".
рекурсивный запрос на такую глубину быстро превращается в нечитаемое месиво
Да ладно, что там нечитаемого-то? преобразуем список рёбер в список полных квалифицированных путей, а там любая задача решается по щелчку пальцев простейшим поиском по шаблону, или, в худшем случае, поиском максимальной общей подстроки. Да, с оптимальностью может быть плоховато, но вот с читаемостью запроса всё в порядке.
Ааа... то есть то, что в описании графа закодировано как SOURCE / DESTINATION, на самом деле есть NODE_1 / NODE_2, а вот уже в тексте запроса задаётся направление отношения. Ну тогда это получается вполне логично - для ненаправленных графов. И требует соответствующей внимательности для направленных, ибо контроль не просто отсутствует, а в принципе синтаксически невозможен.
Судя по структуре хранения вершин и рёбер выше, не содержащих никаких ограничений, поддерживаются кратные и циклические рёбра (петля). А для ненаправленного графа придётся ребро описывать дважды, с различающимися направлениями.
И, поскольку граф есть надстройка над таблицами, на этом уровне вообще никаких констрейнтов не предусмотрено.
как читать направление
То есть получается, что направление задаётся дважды. В структуре - существующее, в запросе.. ммм.. ну, скажем, требуемое. И они обязаны совпадать - иначе будет какая-нибудь бяка типа syntax error или ещё чего. Так, что ли? Если да - то избыточно и странно. А если нет - нужно бы по этому моменту отдельное пояснение.
То есть мало того, что узаконивается звонковый спам, так ещё он теперь обязан будет сопровождаться спамом СМСовским? Вот уж воистину не оскудеет земля русская идиотами.
Прочитал.. Если откровенно - этот процесс надо бы назвать словом "продрался". Ну просто-таки поток неструктурированного сознания. Даже понимая, о чём речь, приходится потратить много внимания, чтобы полностью понять сделанное. И в конце концов оказывается, что статья посвящена решению ну абсолютно стандартной задачи по поиску компонент связности.
В процессе разработки мы протестировали два алгоритма для поиска таких дублирующихся групп
А почему только эти? тем более в PostgreSQL, где есть несколько альтернативных подходов, для которых в СУБД имеются достаточно эффективные средства.
Здесь важен не точный синтаксис SQL, а скорее сам процесс.
Для того, чтобы понять этот самый "скорее сам процесс", синтаксис - ВАЖЕН. Та ерунда, которая приведена как код, не имеет вообще никакого смысла - во-первых, из-за интерференции имён полей, что при отсутствии алиасов превращает код в бардак, во-вторых, из-за отсутствия исходных структур хранения данных. Плюс некоторые тонкости, важные для решения задачи, просто не озвучены - например, причины использования то UNION ALL, то UNION DISTINCT.
А вот это может и не сработать, если под термином "распутывать" вы разумеете замену отрезков строго в четвёрке точек. Потому как переход между имеющейся и оптимальной конфигурацией может включать в путь конфигурацию с бОльшим количеством пересечений или бОльшей суммарной длиной отрезков.
Ограничивать - это экстенсив, от которого мало толку. Логику выполнения на уровне формирования запроса нужно менять. Если встречается что-то типа
AND(0=1ORcat_id=1ORcat_id=2ORcat_id=3)из ~десятка (предел определяется экспериментально) или менее вариантов значения - выполняем как написано, иначе сливаем набор критериев во временную таблицу (которую ещё и проиндексировать можно). Одно дополнительное ветвление в интерактивной части кода и два разных шаблона запроса - потери минимальны, зато эффект налицо.Увы, но я не вижу вообще никаких предпосылок к ОЧЕВИДНОСТИ такого утверждения. С вашим утверждением получается вообще ерунда, а не задача - существует ли конфигурация, которая (по вашим словам) очевидно существует.
Задача-то как раз и состоит в том, чтобы установить, всегда ли существует такая конфигурация.
Вполне возможна ситуация, когда конфигураций с одинаковой минимальной суммой несколько. Это касается и дальнейшего рассуждения - 4 точки могут образовывать квадрат/ромб. Придётся доказывать, что среди таких конфигураций существует та, в которой отсутствуют пересечения.
Правильно для текущей задачи, но некорректно для дополнения про произвольное число цветов и инопланетян. Корректная формулировка - "гарантировать не более одной ошибки".
?? Медленно и плохо - это совершенно разные вещи, медленно - далеко не всегда плохо. Иногда даже что-то приходится специально замедлять (Digger помните? ну или общеизвестное "Быстро, качественно, дёшево - выберите два из трёх"). Нет в мире совершенства, всегда приходится чем-то жертвовать, и иногда это именно скорость.
А что именно тут плохо согласуется-то? По-моему, всё правильно и честно - цитаты вообще о разных вещах говорят, просто они, эти вещи, зависимы. Первая цитата предупреждает, что если нужна точность, то NUMERIC, а не FLOAT/DOUBLE, а вторая дополнительно сообщает, какова будет цена реализации этой требуемой точности.
Увы, это не всегда возможно - сделать все поля NOT NULL. Ведь в этом случае вместо NULL вам необходимо иметь некий default value, который интуитивно понятен, проходит все CHECK, не ломает FK, гарантированно не бывает в рабочем наборе, и при этом не влияет на дальнейшую обработку без добавления специфических условий типа
WHERE .. AND column <> 'не определено'.По-моему, вы меня неправильно понимаете. Я не оспариваю результат сравнения.
Я утверждаю то, что ваше пояснение в скобках ("ноль - это число") не является корректным обоснованием причины неравенства. Из вашего этого пояснения неявным образом формируется вывод, что "а NULL - это НЕ число". И вот этот вывод - он как раз и некорректен, потому что NULL в некоторых ситуациях вполне себе может иметь определённый тип данных. Как в описанном случае, когда этот тип явно определяется типом поля, так и в случае неявного определения типа, если NULL является результатом вычисления функции, и тогда тип значения определён типом возвращаемого функцией значения. В СУБД со строгой типизацией при этом можно даже схватить ошибку сравнения type mismatch, если тип возврата функции не числовой (впрочем, скорее всего эта ошибка вылезет ещё на стадии парсинга).
Я же рассматриваю вполне себе конкретную частную ситуацию. Есть конкретная таблица, в ней есть конкретное поле числового типа, есть конкретная запись, где в этом поле хранится NULL. А вы опять говорите об абстрактной ситуации. Да, определённого числового значения нет, есть NULL как маркер отсутствия значения. Но тип значения у этого маркера отсутствия в описанном случае - есть. И он будет использоваться, несмотря на отсутствие значения - например, если значение является одним из операндов функции COALESCE.
Я не о формулировках, а об их смешении в одном предложении, чего настоятельно советую избегать в данном конкретном случае.
Но COUNT-то NULL не возвращает, а возвращает честный числовой ноль. И плевать ему, что нечего подсчитывать. Почему я и говорю, что об этом бы стоило сказать отдельно и явно - именно для начинающих.
Отож. Когда они реализовали этот оператор, никаким IS NOT DISTINCT FROM в стандарте ещё даже не пахло.
del
Некорректно. Если в данном случае NULL - литерал, то пояснение правильное, но если это значение поля записи числового типа, то он вполне себе число, ибо тип и значение есть разные атрибуты. Хотя он по-прежнему не равен нулю.
Да вполне себе интуитивно. Чтобы получить TRUE, нужно, чтобы все соединяемые через AND значения были TRUE.
Ну это вы сильно запутаете того, кто не в теме. Лучше распишите по отдельности, что WHERE требует TRUE, тогда как CHECK требует что угодно, лишь бы не FALSE.
Следует оговорить, что если все значения в группе есть NULL, то агрегатная функция вернёт-таки NULL. А ещё я бы добавил, что COUNT как раз NULL возвращать не умеет, что для начинающих тоже не всегда очевидно.
Они не единственные. В MySQL/MariaDB давным-давно есть два разных оператора сравнения - обычное compare (
=) и null-safe compare (<=>).Увы, неуниверсально. Далеко не всегда обычный подзапрос можно преобразовать в коррелированный (пусть это и нечастая ситуация). К тому же далеко не факт, что такое преобразование не скажется самым фатальным образом на плане выполнения.
Не все числа вида 6k ± 1 простые. Но вы их всё одно тестируете в качестве "простых делителей".
И непонятно, почему вы не используете готовые списки простых чисел из OEIS.
Хорошо бы ещё узнать, сколько это в процентах от общего числа скончавшихся не по естественным причинам, и на каком месте в таком списке именно эта причина смертности. Возможно, выяснится, что начинать-то надо совсем даже не с авто...
Ага... и потом идентифицировать его по фотографии. Ну класс вообще. Так прямо в свидетельстве о регистрации в графе для VIN и напишем - фотография 800х600px от 01/01/2026. Или засылаем, как на фото выше, с пометкой "мой - третий слева".
Да ладно, что там нечитаемого-то? преобразуем список рёбер в список полных квалифицированных путей, а там любая задача решается по щелчку пальцев простейшим поиском по шаблону, или, в худшем случае, поиском максимальной общей подстроки. Да, с оптимальностью может быть плоховато, но вот с читаемостью запроса всё в порядке.
Ааа... то есть то, что в описании графа закодировано как SOURCE / DESTINATION, на самом деле есть NODE_1 / NODE_2, а вот уже в тексте запроса задаётся направление отношения. Ну тогда это получается вполне логично - для ненаправленных графов. И требует соответствующей внимательности для направленных, ибо контроль не просто отсутствует, а в принципе синтаксически невозможен.
Судя по структуре хранения вершин и рёбер выше, не содержащих никаких ограничений, поддерживаются кратные и циклические рёбра (петля). А для ненаправленного графа придётся ребро описывать дважды, с различающимися направлениями.
И, поскольку граф есть надстройка над таблицами, на этом уровне вообще никаких констрейнтов не предусмотрено.
То есть получается, что направление задаётся дважды. В структуре - существующее, в запросе.. ммм.. ну, скажем, требуемое. И они обязаны совпадать - иначе будет какая-нибудь бяка типа syntax error или ещё чего. Так, что ли? Если да - то избыточно и странно. А если нет - нужно бы по этому моменту отдельное пояснение.
17 машин. По 3 патча. 51 конец. Пополам - не делится. Невозможно.
То есть мало того, что узаконивается звонковый спам, так ещё он теперь обязан будет сопровождаться спамом СМСовским? Вот уж воистину не оскудеет земля русская идиотами.
Прочитал.. Если откровенно - этот процесс надо бы назвать словом "продрался". Ну просто-таки поток неструктурированного сознания. Даже понимая, о чём речь, приходится потратить много внимания, чтобы полностью понять сделанное. И в конце концов оказывается, что статья посвящена решению ну абсолютно стандартной задачи по поиску компонент связности.
А почему только эти? тем более в PostgreSQL, где есть несколько альтернативных подходов, для которых в СУБД имеются достаточно эффективные средства.
Для того, чтобы понять этот самый "скорее сам процесс", синтаксис - ВАЖЕН. Та ерунда, которая приведена как код, не имеет вообще никакого смысла - во-первых, из-за интерференции имён полей, что при отсутствии алиасов превращает код в бардак, во-вторых, из-за отсутствия исходных структур хранения данных. Плюс некоторые тонкости, важные для решения задачи, просто не озвучены - например, причины использования то UNION ALL, то UNION DISTINCT.