Меня всегда восхищали люди, которым хватило сил довести свою работу до конечного продукта, полезного многим (сам я в основном сетевой админ, и, хоть и начинал несколько раз, всегда бросал, чётко понимая, что аналогов куча, и результат будет востребован исключительно мной самим). Респект однозначно.
Но уж позвольте побуквоедствовать. Вы пишете о программном вводе данных. Пожалуйста, не надо. Вы вводите данные исключительно вручную. Программно - это когда вы их считываете с интерфейса аппарата (по какому-нибудь RS485 или даже по Ethernet), когда распознаёте с изображения, снимка, графика и пр. Но ничего подобного у вас даже близко нет.
А ещё - вы пишете следующее:
Программа не позволяет пропустить какие-либо параметры, она их проверяет.
Простите, она проверяет параметры (то есть именно их значение) или только факт того, что они введены? Это совсем разные вещи...
Если в «Аледо-УЗИ-Протокол» полнота введения данных и качество ультразвукового заключения зависело от квалификации врача УЗД, теперь программно вводится полное количество необходимых УЗ-параметров, заключение углубленное и более точное, соответствует пониманию врачом-клиницистом.
Простите, не понял... Если врач просто не вводил какие-то значения по причине малого с его точки зрения их влияния на результат, это одно (которое вообще трудно назвать недостаточной квалификацией, и хочется обозвать низкой степенью ответственности), если врач мог получить значение, но не получал его, потому что его квалификация не позволяла обработать/оценить это значение и использовать при формировании заключения, то это уже немного другое, а если квалификация вообще не позволяла даже получить некоторые значения, так и вовсе даже третье. В любом случае решение требовать всё - очень даже правильное. Правда, при условии, что любой диагностический аппарат гарантированно позволяет получить все эти параметры.
Вроде русским по белому написано: "это определяется именно кодом обработки". Так ведь нет - гарантий же нет, и, значит, это неправда, даже если существующий программный код в принципе не может выйти за пределы указанной зависимости...
Отправка пакета на узел с заданным IP в пределах L2-сегмента выполняется по МАС-адресу этого узла (ARP). Если имеется два узла с одинаковым IP и разными МАС, то невозможно предсказать, какой МАС соответствует данному IP в ARP отправителя. Соответственно кто получит пакет - неизвестно. А поскольку ARP обновляется всякий раз, когда сетевой интерфейс принимает пакет, то зачастую получается, что часть связного потока данных получает один узел, часть другой, в результате ничего не поймут оба.
Microsoft также выпустила обновление для Windows 10, не связанное с безопасностью. KB5061087 (номер сборки 19045.6036) доступен для скачивания и включает в себя различные исправления для меню «Пуск», USB-принтеров, некорректных отчётов о версии Windows и многое другое.
Угу... сегодня после установки указанного обновления на Windows 10 Prof x64 22H2 Rus у некоторых приложений (например, у Калькулятора) начались фортели - приложение открывается сразу на полный экран (у меня два монитора, и приложение, если в нём наблюдается проблема, открывается на втором мониторе, даже если было настроено открываться на первом), а верхняя панель (включая кнопки закрытия и управления размером окна) отсутствует в принципе (не то что не рисуется - просто отсутствует, и доступен видимый кусок десктопа в той полосе, где должна была быть панель).
Откат установки обновления убрал описанные косяки.
Порты fa0/3 и fa0/4 настроены в режиме access, потому что они подключены к обычным ПК и должны принадлежать только к одной VLAN, в нашем случае к Users (VLAN 10).
Не очень корректная фраза. Не "должны принадлежать", а всего лишь "как правило / обычно принадлежат". Вот прямо сейчас пишу с компа, который подключен к порту, работающему в транковом режиме, и могу при необходимости подключиться к любой из 8 имеющихся на порте коммутатора тегованных VLAN (а после дополнительной настройки - к 14 различным VLAN, к любой по выбору или к нескольким одновременно).
Ну даты же могут быть и в будущем, верно? Хотя для штампа времени создания это и правда странненько. С другой стороны, может, время пишется локальное по клиенту, которое запросто может быть уже завтрашним днём.
Хотя в компании с NOT NULL чего только не встретишь в DEFAULT...
Да верю я, что это определяется текущей реализацией, оторую никто не станет менять. Ну типа как порядок вычисления полей в MS Access или MySQL, которые вычисляются строго в порядке текста выходного набора. Там это определяется именно кодом обработки.
Просто бывали прецеденты. Вот все же убеждены, что при простом SELECT * FROM table; данные будут отдаваться в порядке, определяемом первичным ключом, и логика получения данных сервером из хранилища для отдачи клиенту этого требует - а, оказывается, это ни разу не догма, пусть и отклонение встречается весьма редко, а достоверно его воспроизвести вообще без шансов. Или при неполной группировке, буде она допускается сервером, вот тоже все убеждены, что негруппируемые поля будут взяты из одной записи - ан нет. И опять - крайне редко и в принципе невоспроизводимо. Причём если в первом случае a ещё могу придумать причину (горячий покрывающий таблицу вторичный индекс, к примеру), то вот во втором случае мысль просто буксует в попытке придумать механизм.
Это я видел. Но меня лично крайне смущает использованная формулировка, что в переводе. что в оригинале. Она похожа больше не на "это однозначно так", а на "реализация такова, что это так", прям не документация, а словно бабки вечерком на лавочке обсудили. Да, этим можно пользоваться на практике, но вот по моментам с формулировками, подобными этой, постоянно приходится держать в голове, что это current implementation и при любом обновлении может поломаться.
Если база не умеет функциональные индексы (Hello, старый MySQL) — держим нормализованное поле email_lower и триггер на обновление.
Ну или GENERATED COLUMN. В зависимости от СУБД - либо STORED, либо VIRTUAL, но индексированное. И связываем по такому полю.
Хотя правильное решение при нежелании создавать подходящий индекс - не использовать LOWER(), а указать требуемый (регистронезависимый) COLLATE.
LEFT JOIN + WHERE column IS NOT NULL: превращение в INNER JOIN
На самом деле пункт должен быть шире: любой WHERE condition_by_column, за исключением column IS NULL.
В скобках отмечу, что обычно планировщики достаточно умны, чтобы определить, что LEFT JOIN тут не нужен, и выполнить INNER JOIN. Более того, встречался со случаями, когда использование LEFT JOIN в подобном запросе давал более производительный план, чем INNER JOIN - но это действительно экзотика, связанная обычно с достаточно странной (и, как правило, давно не актуализировавшейся) статистикой данных.
Или ставим partial indexes и используем UNION.
Лучше всё же UNION ALL в любом случае, иначе получаем дополнительную и нафиг ненужную сортировку. Просто в одном из подзапросов пишем дополнительное условие: ON condition1 UNION ALL ON condition2 AND NOT condition1 - это будет тем быстрее, чем больше выходной набор.
Не-саргабельные выражения (DATE(created_at) = …)
Ну вообще-то уже был пункт JOIN по функции (LOWER(email)), который именно об этом. Какой смысл делить на два пункта только потому, что non-SARGable условие располагается в разных секциях запроса?
Реписываем на оконные функции:
Во-первых, опечатка.
Во-вторых - и это главное,- покажите мне там оконную функцию. В упор не вижу.
А ещё - DISTINCT ON есть чисто Постгрессовская конструкция. И, покопавшись в его документации, я так и не нашёл нигде явного указания, что при использовании DISTINCT ON + ORDER BY в выходной набор попадёт именно топ-запись по указанной сортировке. А без такой гарантии запрос превратится в тыкву... может, я плохо искал? ткните пальцем, пожалуйста, в соотв. пункт документации.
Встраиваемые СУБД. Легкие системы, встроенные прямо в приложение.
Встраиваемые СУБД по способу работы являются обычными клиент-серверными СУБД. От "полноценных" клиент-серверных они отличаются только тем, что серверная часть не является самостоятельным приложением, а встраивается в клиентское приложение.
Здесь не нужно:
следить за обновлениями версий и рисковать при каждом апгрейде;
Не понял... речь об обновлении чего речь - клиентского приложения, которое обращается к БД, или об обновлении версии СУБД?
Если второе - то ещё как нужно! Точнее, нужно следить, чтобы предоставляемый сервис, не дай бог, чего не обновил...
Это не всегда верно. Если их просто выкинуть и не вносить иных правок, то большинство СУБД выдаст ошибку синтаксиса из-за некорректного местоположения второго ON (или из-за отсутствия ON в первом JOIN - зависит от СУБД). Перемещение же второго ON в LEFT OUTER JOIN для получения синтаксически корректного кода выдаст ошибку, если в его выражении используются поля из t3.
Рассмотрим на примере (пример №1), когда заказчик говорит: «У пользователя может быть только одна активная подписка». Разработчик создает таблицу subscription с полем is_active.
Что забыли учесть?
То, что активная подписка - это атрибут сущности пользователь, а не атрибут сущности подписка. То есть разработчик накосячил. Например, он должен был в таблицу пользователей добавить поле active_subscription, которое является внешней ссылкой на таблицу подписок.
Требование заказчика: «Пользователь может сменить тариф, но мы должны сохранять историю изменений для аналитики». Разработчик создает таблицы subscription и tariff и добавляет в subscriptions поле tariff_id.
Что пошло не так?
Ну так опять разработчик накосорезил... Просто проигнорировал требования заказчика. Гоните его в шею.
«Радиоволны, которые мы обнаружили, шли под очень крутым углом, — говорит Виссел в пресс-релизе, — примерно на 30 градусов ниже поверхности льда».
В оригинале:
The radio waves that we detected nearly a decade ago were at really steep angles, like 30 degrees below the surface of the ice
Если он имел в виду, что радиоволны идут внутрь льда, вниз, под углом в 30 градусов к поверхности, то в каком, простите, месте они эти радиоволны регистрировали? Сами в лёд зарывались, что ли? Ага, вместе с воздушными шарами...
Я именно про это. В вашем случае высший приоритет у скобки, и сперва связываются t2 и t3, а потом t1 связывается с полученным результатом. И, с учётом приоритета и видимости, в условии связывания t2 и t3 нельзя использовать поля из t1, ибо получим unknown table.
Ради любопытства - разберите порядок связывания и области видимости в источнике
FROM t1, t2 JOIN (t3 JOIN t4, t5 JOIN t6)
Ну и ещё неявно про разницу между FROM t1 CROSS JOIN t2 и FROM t1, t2. Сколько раз встречал вопросы типа: почему FROM t1 CROSS JOIN t2 INNER JOIN t3 ON t3.x=t1.x AND t3.y=t2.y работает, а FROM t1, t2 INNER JOIN t3 ON t3.x=t1.x AND t3.y=t2.y приводит к ошибке.
Ну то есть сперва создаём себе трудности, а потом их мужественно преодолеваем. Странно всё это...
Нет, я допускаю случаи (и даже работал с таковыми), когда приходящие исходные данные, прямо скажем, грязненькие, и в строгую структуру не ложатся. Но это вполне себе решается хранением и "сырого" значения, и нормализованного, со связью между ними. А данные, которые не удалось распознать в автоматическом режиме, или которые приводят к коллизии, выводятся в третью таблицу - требующую вмешательства оператора и ручной интерпретации. Но в любом случае на выход подаются только надёжные, проверенные данные. Либо по специальному запросу - сырые, но уж коли запросил такое, то не жалуйся на скорость.
Господи, ну сколько же можно, не думая. переписывать одно и то же друг у друга, а?
Оператор FROM
Оператор JOIN
Оператор WHERE
Оператор GROUP BY
Оператор HAVING
Оператор ORDER BY
Операторы OFFSET и LIMIT
Оператор SELECT
Во-первых, у вас, как и у всех ваших предшественников, пропущен пункт "оконные функции". который НЕОБХОДИМО в таком списке указывать отдельно - масса проблем возникает именно из-за непонимания местоположения этого шага в формальном роадмапе исполнения запроса.
Во-вторых, у вас нет дополнительного описания того, где в этом списке находятся коррелированные, в т.ч. и латеральные, подзапросы.
Компрометация за год до окончания срока действия и через год после как бы если и не равновероятны, то различаются по этому параметру весьма несильно.
Меня всегда восхищали люди, которым хватило сил довести свою работу до конечного продукта, полезного многим (сам я в основном сетевой админ, и, хоть и начинал несколько раз, всегда бросал, чётко понимая, что аналогов куча, и результат будет востребован исключительно мной самим). Респект однозначно.
Но уж позвольте побуквоедствовать. Вы пишете о программном вводе данных. Пожалуйста, не надо. Вы вводите данные исключительно вручную. Программно - это когда вы их считываете с интерфейса аппарата (по какому-нибудь RS485 или даже по Ethernet), когда распознаёте с изображения, снимка, графика и пр. Но ничего подобного у вас даже близко нет.
А ещё - вы пишете следующее:
Простите, она проверяет параметры (то есть именно их значение) или только факт того, что они введены? Это совсем разные вещи...
Простите, не понял... Если врач просто не вводил какие-то значения по причине малого с его точки зрения их влияния на результат, это одно (которое вообще трудно назвать недостаточной квалификацией, и хочется обозвать низкой степенью ответственности), если врач мог получить значение, но не получал его, потому что его квалификация не позволяла обработать/оценить это значение и использовать при формировании заключения, то это уже немного другое, а если квалификация вообще не позволяла даже получить некоторые значения, так и вовсе даже третье. В любом случае решение требовать всё - очень даже правильное. Правда, при условии, что любой диагностический аппарат гарантированно позволяет получить все эти параметры.
:applause:
Вроде русским по белому написано: "это определяется именно кодом обработки". Так ведь нет - гарантий же нет, и, значит, это неправда, даже если существующий программный код в принципе не может выйти за пределы указанной зависимости...
Даже когда создаётся прямой р2р мост с маской /32?
Отправка пакета на узел с заданным IP в пределах L2-сегмента выполняется по МАС-адресу этого узла (ARP). Если имеется два узла с одинаковым IP и разными МАС, то невозможно предсказать, какой МАС соответствует данному IP в ARP отправителя. Соответственно кто получит пакет - неизвестно. А поскольку ARP обновляется всякий раз, когда сетевой интерфейс принимает пакет, то зачастую получается, что часть связного потока данных получает один узел, часть другой, в результате ничего не поймут оба.
Угу... сегодня после установки указанного обновления на Windows 10 Prof x64 22H2 Rus у некоторых приложений (например, у Калькулятора) начались фортели - приложение открывается сразу на полный экран (у меня два монитора, и приложение, если в нём наблюдается проблема, открывается на втором мониторе, даже если было настроено открываться на первом), а верхняя панель (включая кнопки закрытия и управления размером окна) отсутствует в принципе (не то что не рисуется - просто отсутствует, и доступен видимый кусок десктопа в той полосе, где должна была быть панель).
Откат установки обновления убрал описанные косяки.
Не очень корректная фраза. Не "должны принадлежать", а всего лишь "как правило / обычно принадлежат". Вот прямо сейчас пишу с компа, который подключен к порту, работающему в транковом режиме, и могу при необходимости подключиться к любой из 8 имеющихся на порте коммутатора тегованных VLAN (а после дополнительной настройки - к 14 различным VLAN, к любой по выбору или к нескольким одновременно).
Ну даты же могут быть и в будущем, верно? Хотя для штампа времени создания это и правда странненько. С другой стороны, может, время пишется локальное по клиенту, которое запросто может быть уже завтрашним днём.
Хотя в компании с NOT NULL чего только не встретишь в DEFAULT...
Да верю я, что это определяется текущей реализацией, оторую никто не станет менять. Ну типа как порядок вычисления полей в MS Access или MySQL, которые вычисляются строго в порядке текста выходного набора. Там это определяется именно кодом обработки.
Просто бывали прецеденты. Вот все же убеждены, что при простом
SELECT * FROM table;
данные будут отдаваться в порядке, определяемом первичным ключом, и логика получения данных сервером из хранилища для отдачи клиенту этого требует - а, оказывается, это ни разу не догма, пусть и отклонение встречается весьма редко, а достоверно его воспроизвести вообще без шансов. Или при неполной группировке, буде она допускается сервером, вот тоже все убеждены, что негруппируемые поля будут взяты из одной записи - ан нет. И опять - крайне редко и в принципе невоспроизводимо. Причём если в первом случае a ещё могу придумать причину (горячий покрывающий таблицу вторичный индекс, к примеру), то вот во втором случае мысль просто буксует в попытке придумать механизм.Это я видел. Но меня лично крайне смущает использованная формулировка, что в переводе. что в оригинале. Она похожа больше не на "это однозначно так", а на "реализация такова, что это так", прям не документация, а словно бабки вечерком на лавочке обсудили. Да, этим можно пользоваться на практике, но вот по моментам с формулировками, подобными этой, постоянно приходится держать в голове, что это current implementation и при любом обновлении может поломаться.
Три нуля потеряли...
Ну или
GENERATED COLUMN
. В зависимости от СУБД - либоSTORED
, либоVIRTUAL
, но индексированное. И связываем по такому полю.Хотя правильное решение при нежелании создавать подходящий индекс - не использовать
LOWER()
, а указать требуемый (регистронезависимый)COLLATE
.На самом деле пункт должен быть шире: любой
WHERE condition_by_column
, за исключениемcolumn IS NULL
.В скобках отмечу, что обычно планировщики достаточно умны, чтобы определить, что LEFT JOIN тут не нужен, и выполнить INNER JOIN. Более того, встречался со случаями, когда использование LEFT JOIN в подобном запросе давал более производительный план, чем INNER JOIN - но это действительно экзотика, связанная обычно с достаточно странной (и, как правило, давно не актуализировавшейся) статистикой данных.
Лучше всё же UNION ALL в любом случае, иначе получаем дополнительную и нафиг ненужную сортировку. Просто в одном из подзапросов пишем дополнительное условие:
ON condition1 UNION ALL ON condition2 AND NOT condition1
- это будет тем быстрее, чем больше выходной набор.Ну вообще-то уже был пункт JOIN по функции (LOWER(email)), который именно об этом. Какой смысл делить на два пункта только потому, что non-SARGable условие располагается в разных секциях запроса?
Во-первых, опечатка.
Во-вторых - и это главное,- покажите мне там оконную функцию. В упор не вижу.
А ещё -
DISTINCT ON
есть чисто Постгрессовская конструкция. И, покопавшись в его документации, я так и не нашёл нигде явного указания, что при использованииDISTINCT ON + ORDER BY
в выходной набор попадёт именно топ-запись по указанной сортировке. А без такой гарантии запрос превратится в тыкву... может, я плохо искал? ткните пальцем, пожалуйста, в соотв. пункт документации.Встраиваемые СУБД по способу работы являются обычными клиент-серверными СУБД. От "полноценных" клиент-серверных они отличаются только тем, что серверная часть не является самостоятельным приложением, а встраивается в клиентское приложение.
Не понял... речь об обновлении чего речь - клиентского приложения, которое обращается к БД, или об обновлении версии СУБД?
Если второе - то ещё как нужно! Точнее, нужно следить, чтобы предоставляемый сервис, не дай бог, чего не обновил...
Мне кажется достаточно удачным для перевода clause использование термина "секция". И чуть менее удачным - "раздел".
Это не всегда верно. Если их просто выкинуть и не вносить иных правок, то большинство СУБД выдаст ошибку синтаксиса из-за некорректного местоположения второго ON (или из-за отсутствия ON в первом JOIN - зависит от СУБД). Перемещение же второго ON в LEFT OUTER JOIN для получения синтаксически корректного кода выдаст ошибку, если в его выражении используются поля из t3.
То, что активная подписка - это атрибут сущности пользователь, а не атрибут сущности подписка. То есть разработчик накосячил. Например, он должен был в таблицу пользователей добавить поле active_subscription, которое является внешней ссылкой на таблицу подписок.
Ну так опять разработчик накосорезил... Просто проигнорировал требования заказчика. Гоните его в шею.
Дальше даже не смотрел...
Блин, так и не смог понять фразу:
В оригинале:
Если он имел в виду, что радиоволны идут внутрь льда, вниз, под углом в 30 градусов к поверхности, то в каком, простите, месте они эти радиоволны регистрировали? Сами в лёд зарывались, что ли? Ага, вместе с воздушными шарами...
Я именно про это. В вашем случае высший приоритет у скобки, и сперва связываются t2 и t3, а потом t1 связывается с полученным результатом. И, с учётом приоритета и видимости, в условии связывания t2 и t3 нельзя использовать поля из t1, ибо получим unknown table.
Ради любопытства - разберите порядок связывания и области видимости в источнике
FROM t1, t2 JOIN (t3 JOIN t4, t5 JOIN t6)
Ну и ещё неявно про разницу между
FROM t1 CROSS JOIN t2
иFROM t1, t2
. Сколько раз встречал вопросы типа: почемуFROM t1 CROSS JOIN t2 INNER JOIN t3 ON t3.x=t1.x AND t3.y=t2.y
работает, аFROM t1, t2 INNER JOIN t3 ON t3.x=t1.x AND t3.y=t2.y
приводит к ошибке.Join - это самое обычное выражение, которое может включать три операции (в порядке снижения приоритета):
скобка
явный JOIN
запятая (неявный JOIN)
Всё, что нужно - это в правильных местах размещать условия связывания и следить за видимостью и текущими алиасами.
Ну то есть сперва создаём себе трудности, а потом их мужественно преодолеваем. Странно всё это...
Нет, я допускаю случаи (и даже работал с таковыми), когда приходящие исходные данные, прямо скажем, грязненькие, и в строгую структуру не ложатся. Но это вполне себе решается хранением и "сырого" значения, и нормализованного, со связью между ними. А данные, которые не удалось распознать в автоматическом режиме, или которые приводят к коллизии, выводятся в третью таблицу - требующую вмешательства оператора и ручной интерпретации. Но в любом случае на выход подаются только надёжные, проверенные данные. Либо по специальному запросу - сырые, но уж коли запросил такое, то не жалуйся на скорость.
Господи, ну сколько же можно, не думая. переписывать одно и то же друг у друга, а?
Во-первых, у вас, как и у всех ваших предшественников, пропущен пункт "оконные функции". который НЕОБХОДИМО в таком списке указывать отдельно - масса проблем возникает именно из-за непонимания местоположения этого шага в формальном роадмапе исполнения запроса.
Во-вторых, у вас нет дополнительного описания того, где в этом списке находятся коррелированные, в т.ч. и латеральные, подзапросы.