Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Базы данных: SQL > Как работают вычисления в SQL?


Автор: rownong@yandex.ru 26.12.23, 15:14
Здравствуйте.
Работаю с базой данный через PhpMyAdmin.
В нем можно отправлять SQL запросы к базе и в интерфейсе PhpMyAdmin видеть результат. Заинтересовали расчеты с помощью SQL. Помогите с ними разобраться.

Пример 1.
Есть Таблица с одинаковым товаром, с полями
- номер заказа
- количество проданного товара
- стоимость товара за штуку

Можно ли с помощью SQL посчитать сумму за каждый заказ умножив
(количество проданного товара)*(стоимость товара за штуку)?

Где в таком случае выведется результат произведения?
Будет создан абстрактный (временный) столбец, где выведутся произведения для каждого заказа?
Объясните, пожалуйста, как это работает.

--

Пример 2.
Есть таблицы с полями
- Номер заказа
- Статус заказа
- Дата время наступления статуса

Строка 1:
- Номер заказа: "123"
- Статус заказа: "Создан"
- Дата время наступления статуса: "01.12.2023"

Строка 2:
- Номер заказа: "123"
- Статус заказа: "Завершен"
- Дата время наступления статуса: "03.12.2023"

Нужно посчитать с помощью SQL сколько дней для Заказа "123" прошло между статусам "Создан" и "Завершен".
Т.е. "03.12.2023" - "01.12.2023" = 2дня
Можно ли это посчитать через SQL?
Вопрос аналогичный, где будет выведен результат?
Будет создана абстрактная (временная) таблица в которой будут выведены
- Номер заказа
- Количество дней между прошло между статусам "Создан" и "Завершен".
??

user posted image

Автор: Majestio 26.12.23, 17:15
Цитата rownong@yandex.ru @
Можно ли это посчитать через SQL?

Конечно можно. Для этого тебе нужно сделать соединение таблицы с самой себя. Условие соединения - что номера заказов совпадают, и у первой таблицы в поле статуса заказа "создан", и у второй "завершен". В этом запросе в блоке SELECT указываешь первым полем - номер заказа (первой или присоединяемой таблицы - без разницы, т.к. они равны), вторым полем используешь функцию с постфикcом AS days. Этим самым ты переназовешь второй столбец. Функцию ищи в документации, которая рассчитывает разницу в днях. Если я не ошибаюсь - в MySQL это DATEDIFF. В PostgreSQL используй что-то типа:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    (timestamp2::date - timestamp1::date) AS days


Добавлено
Цитата rownong@yandex.ru @
Вопрос аналогичный, где будет выведен результат?
Будет создана абстрактная (временная) таблица в которой будут выведены
- Номер заказа
- Количество дней между прошло между статусам "Создан" и "Завершен".
??

Будет создан результат, который будет выведен в интерфейс phpMyAdmin, и никуда не будет записан. Если нужно его куда-то сохранить - копируй из интерфейса копипастой. Или создай заранее нужную таблицу в БД и в нее произведи запись результата запроса.

Автор: Akina 26.12.23, 19:49
Цитата rownong@yandex.ru @
Где в таком случае выведется результат произведения?

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

Например, запрос может выглядеть так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    SELECT table1.name1, table2.name2 AS name3, table1.name4 * table2.name5 AS name6
    FROM ...

Соответственно после связывания исходных таблиц в соответствии в секцией FROM, фильтрации в соответствии со WHERE и сортировкой в соответствии с ORDER BY будет возвращён набор записей. Он будет состоять из трёх полей с именами name1, name3 и name6, первые два будут содержать неизменённые значения указанных полей исходных таблиц, третье - произведение указанных полей.

Автор: rownong@yandex.ru 29.12.23, 01:15
Цитата
В запросе, который описывает задание серверу, указывается, какие поля нужно вернуть, и с помощью каких выражений следует получать для них значения. Можно вывести поле исходной таблицы без изменения, можно его при выводе переименовать, можно на основе нескольких полей написать вычисляющее выражение и дать ему имя...

Получается когда делаем SQL запрос, чтобы соединить 2 таблицы можем в результате скрывать (не выводить) определённые столбцы? Вернее, выводить только нужны столбцы из обоих таблиц

Добавлено
Если есть например 10 менеджеров по продажам, мы можем в результате SQL запроса вывести не 10 строка с суммой продажи каждого менеджера за месяц, а 1 строк с суммой продаж всех менеджеров за месяц?

Автор: Majestio 29.12.23, 04:04
Цитата rownong@yandex.ru @
Получается когда делаем SQL запрос, чтобы соединить 2 таблицы можем в результате скрывать (не выводить) определённые столбцы? Вернее, выводить только нужны столбцы из обоих таблиц

Да.
Цитата rownong@yandex.ru @
Если есть например 10 менеджеров по продажам, мы можем в результате SQL запроса вывести не 10 строка с суммой продажи каждого менеджера за месяц, а 1 строк с суммой продаж всех менеджеров за месяц?

Можем. Есть несколько вариантов. Первый - используй фильтрацию запросов оператором WHERE чтобы получить одну нужную строку, либо пробуй использовать оператор LIMIT с аргументом 1. Во втором случае скорее всего нужно будет прибегнуть заранее к сортировке строк результата, ибо лимит только "обрежет" остальные строки из результата. А без предварительной сортировки это будет недетерминированный результат.

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

Автор: Akina 29.12.23, 07:05
Цитата rownong@yandex.ru @
Получается когда делаем SQL запрос, чтобы соединить 2 таблицы можем в результате скрывать (не выводить) определённые столбцы? Вернее, выводить только нужны столбцы из обоих таблиц

Выводить нужно (не можно, а именно нужно) только то, что реально требуется. Если нужны только результаты вычисления каких-то выражений - в выходном наборе должны быть только они. SELECT * в рабочей версии приложения пишут исключительно идиоты (да, вот настолько безальтернативно) - даже если действительно нужны все поля, следует их перечислять по одному. Или идти учить матчасть по нормализации данных.

Цитата rownong@yandex.ru @
Если есть например 10 менеджеров по продажам, мы можем в результате SQL запроса вывести не 10 строка с суммой продажи каждого менеджера за месяц, а 1 строк с суммой продаж всех менеджеров за месяц?

Продажа отдельного менеджера и продажа всех менеджеров - это разные уровни группировки. Поэтому сама фраза не имеет смысла - нужно ведь либо то, либо другое. А если вдруг надо всё это одновременно (программист не умеет заставить клиентскую часть выводить итоги), то есть GROUP BY WITH ROLLUP/CUBE. Нереляционно, но если по другому не умеешь - пусть его. Это ж потом не SQL-серверу трахаться, а клиентской части, её не жалко.

Автор: Majestio 29.12.23, 08:17
Цитата Akina @
SELECT * в рабочей версии приложения пишут исключительно идиоты (да, вот настолько безальтернативно) - даже если действительно нужны все поля, следует их перечислять по одному

Согласен полностью. Но только с учетом именно рабочей версии. В процессе написания скрипта и его отладки SELECT * вполне допустимо использовать, иногда это немного экономит время. ИМХО.

Автор: MIF 29.12.23, 13:50
SELECT * можно писать в рабочем коде. Вот MS SQL пример:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    IF EXISTS(SELECT * …

Есть еще по крайней мере один случай, когда нельзя перечислять поля, а надо писать SELECT * в рабочем коде.

Автор: Majestio 29.12.23, 17:21
Цитата MIF @
надо писать SELECT * в рабочем коде

Хм...Это с какого такого перепугу? :P

Автор: Akina 30.12.23, 09:16
Цитата MIF @
SELECT * можно писать в рабочем коде. Вот MS SQL пример:

Вас спасает только то, что MS SQL достаточно умный. И знает, что в EXISTS сами значения полей не нужны, и лезть за ними в тело таблицы не требуется. Но вот формально - такой код требует метнуться за значениями полей, а потому SELECT {const} разумнее и логичнее.

Цитата MIF @
Есть еще по крайней мере один случай, когда нельзя перечислять поля, а надо писать SELECT * в рабочем коде.

Хотелось бы конкретики. Я пока о таких случаях не слышал - за исключением ситуации, когда необходимость грести всё подряд определяется или отставанием клиента, или мультиверсионностью БД.

Автор: rownong@yandex.ru 02.01.24, 09:18
Еще подскажите:

1. При SQL запросе, когда создаем абстрактные (не существующие) поле (столбцы) можно ли кроме присвоения им имен, также добавлять комментарии, на время просмотра SQL запроса?
Аналогично как это сделано например в PhpMyAdmin для обычных полей (столбцов)?

2. Какой оператор нужно использовать, чтобы использовать фильтр типа "содержит"?
Например выбрать все записи из table1, в которых поле log содержит текст "395948"

Пример значений поля log
{"items_data":[{"item_sid":"7069294","qty":1}],"contact_phone":"79777777777","contact_name":"u0421u043eu0431u0441u0442u0432u0435u043du043du0430u044f u0437u0430u044fu0432u043au0430","contact_email":"service@yandex.ru","jp_purchase_id":"395948"}

{"items_data":[{"item_sid":"2388062","qty":2}],"contact_phone":"79777777777","contact_name":"u0421u043eu0431u0441u0442u0432u0435u043du043du0430u044f u0437u0430u044fu0432u043au0430","contact_email":"service@yandex.ru","jp_purchase_id":"395948"}

Интересует как это указывать в запросе и в фильтре PhpMyAdmin.
user posted image
user posted image

Автор: Akina 02.01.24, 18:36
Цитата rownong@yandex.ru @
1. При SQL запросе, когда создаем абстрактные (не существующие) поле (столбцы) можно ли кроме присвоения им имен, также добавлять комментарии, на время просмотра SQL запроса?

Нет.

Цитата rownong@yandex.ru @
2. Какой оператор нужно использовать, чтобы использовать фильтр типа "содержит"?

Показанные примеры не относятся к типу "содержит". Это типичный случай "равно" (использован синтаксис MySQL):
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    WHERE log->>"$.jp_purchase_id" = '395948'

Автор: rownong@yandex.ru 05.01.24, 22:38
Цитата Akina @
Цитата rownong@yandex.ru @
1. При SQL запросе, когда создаем абстрактные (не существующие) поле (столбцы) можно ли кроме присвоения им имен, также добавлять комментарии, на время просмотра SQL запроса?

Нет.

Цитата rownong@yandex.ru @
2. Какой оператор нужно использовать, чтобы использовать фильтр типа "содержит"?

Показанные примеры не относятся к типу "содержит". Это типичный случай "равно" (использован синтаксис MySQL):
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    WHERE log->>"$.jp_purchase_id" = '395948'

Спасибо!

Автор: rownong@yandex.ru 05.01.24, 22:38
Подскажите, правильно понимаю, что результатом SQL запроса могут быть:
1. Реальная таблица из БД.
2. Абстрактная таблица (с несуществующими столбцами, но которые создаем в момент запроса)
3. Число (например результат расчетов). Т.е. просто одно число (без таблиц и столбцов), которое получаем в результате.
??

Автор: Majestio 05.01.24, 23:08
Цитата rownong@yandex.ru @
Подскажите, правильно понимаю, что результатом SQL запроса могут быть:
1. Реальная таблица из БД.
2. Абстрактная таблица (с несуществующими столбцами, но которые создаем в момент запроса)
3. Число (например результат расчетов). Т.е. просто одно число (без таблиц и столбцов), которое получаем в результате.

Не совсем правильно. Результатом SQL запроса не может быть ни реальная таблица из БД, ни абстрактная таблица, и ни число. Ибо результатом SQL запроса может быть только сам результат SQL запроса :)

Другое дело, что может содержать этот результат. А он может содержать:

1. Значения всех или отдельных полей (столбцов) реальной таблицы или таблиц из БД
2. Значения полей (столбцов), получаемых в результате вычислений, обращений к VIEW или хранимым процедурам
3. Значения полей (столбцов), заданных константой

Последний вариант, скажем так, сильно менее распространён. Как правило используется в подзапросах. Ибо в финальном запросе указывать поле, содержащее константу, по факту - бессмысленно.

Автор: Majestio 05.01.24, 23:29
Цитата Akina @
Нет.

Он скорее всего некорректно задал вопрос :lol: Возможно речь шла о формировании "комментария" (по факту обычного поля), а-ля:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    SELECT
      name AS Name,
      cnt AS Cnt ,
      CASE WHEN cnt > 100500 THEN 'дофига' ELSE 'так себе' END AS Comment;


Хотя - это только мои догадки.

Автор: macomics 06.01.24, 00:44
Цитата Majestio @
Цитата Akina @
Нет.

Он скорее всего некорректно задал вопрос :lol: Возможно речь шла о формировании "комментария" (по факту обычного поля), а-ля:

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    SELECT
      name AS Name,
      cnt AS Cnt ,
      CASE WHEN cnt > 100500 THEN 'дофига' ELSE 'так себе' END AS Comment;


Хотя - это только мои догадки.

Нет. Он спрашивал о комментариях. Они могут быть добавлены к полям таблицы при создании.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    CREATE TABLE IF NOT EXISTS `BIO` (`id` INT PRIMARY KEY COMMENT 'Main key', `name` VARCHAR(64) COMMENT 'Имя', `sername` VARCHAR(64) COMMENT 'Фамилия', `male` INT(1) COMMENT 'Пол мужской?')


Вот об этих комментариях он спрашивал

https://dev.mysql.com/doc/refman/8.0/en/create-table.html

Автор: Majestio 06.01.24, 06:54
Цитата macomics @
Вот об этих комментариях он спрашивал

https://dev.mysql.com/doc/refman/8.0/en/create-table.html

А, понятно :good:

Автор: Akina 06.01.24, 08:25
Цитата rownong@yandex.ru @
Подскажите, правильно понимаю, что результатом SQL запроса могут быть:
1. Реальная таблица из БД.
2. Абстрактная таблица (с несуществующими столбцами, но которые создаем в момент запроса)
3. Число (например результат расчетов). Т.е. просто одно число (без таблиц и столбцов), которое получаем в результате.
??

Совершенно неправильно.

Есть запросы, которые возвращают набор данных. Т.е. которые возвращают результат выборки/расчёта. Даже если результатом является единственная запись с единственным полем (то, что тебе кажется "просто числом"). Даже если результатом является пустой, не содержащий ни одной записи, набор.

И есть запросы, которые НЕ возвращают набор данных. Это запросы, которые модифицируют данные (если диалект не поддерживает RETURNING или если он не использован), а также запросы, которые работают с метаданными. Такие запросы возвращают статус выполненного запроса и, возможно, дополнительную информацию по его выполнению (например, запрос на обновление возвращает как общее количество записей, соответствующих условиям отбора, так и количество фактически обновлённых записей, т.е. в которых новое значение отличается от старого).

Кроме того, выполнение абсолютно любого запроса может привести к ошибке - в этом случае возвращается код ошибки и дополнительная информация по ней.

Автор: Majestio 06.01.24, 12:12
Цитата Akina @
Совершенно неправильно.

Есть запросы, которые возвращают набор данных. Т.е. которые возвращают результат выборки/расчёта. Даже если результатом является единственная запись с единственным полем (то, что тебе кажется "просто числом"). Даже если результатом является пустой, не содержащий ни одной записи, набор.

И есть запросы, которые НЕ возвращают набор данных. Это запросы, которые модифицируют данные (если диалект не поддерживает RETURNING или если он не использован), а также запросы, которые работают с метаданными. Такие запросы возвращают статус выполненного запроса и, возможно, дополнительную информацию по его выполнению (например, запрос на обновление возвращает как общее количество записей, соответствующих условиям отбора, так и количество фактически обновлённых записей, т.е. в которых новое значение отличается от старого).

Кроме того, выполнение абсолютно любого запроса может привести к ошибке - в этом случае возвращается код ошибки и дополнительная информация по ней.

Не согласен, потому как речь шла именно о запросах по получению данных. Другие запросы, модифицирующие прикладные данные, системную информацию - об этом не шла речь. Равно как и о запросах с ошибкой.

Автор: rownong@yandex.ru 06.01.24, 20:57
Цитата rownong@yandex.ru @
3. Число (например результат расчетов). Т.е. просто одно число (без таблиц и столбцов), которое получаем в результате.
??

По этому вопросу в итоге непонял, результат SQL моежет быть только 1 число - результат вычислений?

Автор: macomics 06.01.24, 21:23
Цитата rownong@yandex.ru @
По этому вопросу в итоге непонял, результат SQL моежет быть только 1 число - результат вычислений?

Даже одно число можно представить в виде одной строки с одним столбцом.
Результатом запроса будут именно подобные значения (строки и столбцы). Столбцы перечисляются в запросе, а строки формируются по результатам отбора из базы данных.
При этом результатом запроса может быть одно значение, но для его размещения будет сформировано одно поле и выбрана одна строка.

Так надеюсь понятнее.

Автор: Akina 06.01.24, 22:18
Цитата rownong@yandex.ru @
По этому вопросу в итоге непонял, результат SQL моежет быть только 1 число - результат вычислений?

Нет.

Как уже выше сказано, это будет набор записей. Сам набор будет состоять из одной записи, а структура набора (и соответственно этой одной записи) будет состоять из одного поля. Как итог - весь набор записей будет содержать ровно 1 запись * 1 поле = 1 значение. Но набор записей содержит ещё кучу метаданных - количество полей (одно), имя этого одного поля, тип его данных, количество записей (одна)...

Соответственно обратиться к этому набору как к скалярному значению - нельзя. Хорошо, если при обращении будет выполнено неявное приведение к скалярному типу - то есть удалена метаинформация об имени поля и типе его данных и пр... но надеяться на это неразумно, да и вероятность существования в синтаксисе такого неявного приведения весьма мала. Например, тот же MySQL вроде бы делает это с лёгкостью - ага, как бы не так! для того, чтобы он преобразовал, надо выражение-запрос обернуть скобками, иначе syntax error.

Автор: rownong@yandex.ru 15.01.24, 18:32
Подскажите в SQL запросе возможно построить абстрактную (виртуальную) таблицу следующего вида, где показатели идут не в столбцах а в строках? Т.е. из разных таблиц собрать временные столбцы и строки такого вида как на скрине. Грубо говоря мини-дашборд.
user posted image

Автор: Akina 15.01.24, 19:32
Цитата rownong@yandex.ru @
Подскажите в SQL запросе возможно построить абстрактную (виртуальную) таблицу

Нет. Применительно к SQL такого понятия как "абстрактная (виртуальная) таблица" - не существует.

Используйте корректную технически грамотную терминологию.

Автор: rownong@yandex.ru 15.01.24, 21:01
Цитата rownong@yandex.ru @
Подскажите в SQL запросе возможно построить абстрактную (виртуальную) таблицу следующего вида, где показатели идут не в столбцах а в строках? Т.е. из разных таблиц собрать временные столбцы и строки такого вида как на скрине. Грубо говоря мини-дашборд.
user posted image

А что по поводу этого вопроса? Такое решение реально сделать?

Автор: Majestio 16.01.24, 13:35
Цитата rownong@yandex.ru @
А что по поводу этого вопроса? Такое решение реально сделать?

Абстрактных (виртуальных) таблиц в SQL не существует, но есть VIEW (представления), которые реализуют твои потребности по данному вопросу.
Материала по этому в сети полно. Навскидку, почитай вот эту статью. Статья более-менее норм, имхо.

Автор: rownong@yandex.ru 19.01.24, 13:39
Еще подскажите, создавая временные (виртуальные) поля (столбцы) в результате SQL запроса, можно им имена давать не на латинице, а на кириллице и с пробелами?

Автор: macomics 19.01.24, 14:07
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    SELECT
        id as 'идентификатор',
        name as 'имя',
        sername as 'фамилия',
        extname as 'отчество',
        birthday as 'дата рождения'
     FROM BIOData;
Что мешает попробовать? Это на MSSQL - работает.

https://sqliteonline.com/

Для тренировки и уменьшения количества вопросов

Автор: rownong@yandex.ru 19.01.24, 14:21
Цитата macomics @
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    SELECT
        id as 'идентификатор',
        name as 'имя',
        sername as 'фамилия',
        extname as 'отчество',
        birthday as 'дата рождения'
     FROM BIOData;
Что мешает попробовать? Это на MSSQL - работает.

https://sqliteonline.com/

Для тренировки и уменьшения количества вопросов

Отлично! Спасибо!

Автор: rownong@yandex.ru 19.01.24, 16:18
Попробовал просто на кириллице одинарные слова или несколько через нижнее подчеркивание, все ок.
А вот когда через пробел слова, даже в кавычках вся фраза, то заглючивает SQL запрос.

Автор: rownong@yandex.ru 20.01.24, 07:34
Подскажите, если есть столбце с полем артикул и в каждой строке перед артикулом приставка "1-" (например 1-23442242), то как вырезать эту приставку "1-" SQL-ем чтобы далее производить вычисления чистым артикулом?

Автор: Akina 20.01.24, 16:50
Цитата rownong@yandex.ru @
как вырезать эту приставку "1-" SQL-ем

Зависит от СУБД и даже точной версии - везде свои встроенные строковые функции.

Автор: rownong@yandex.ru 20.01.24, 19:23
Цитата Akina @
Цитата rownong@yandex.ru @
как вырезать эту приставку "1-" SQL-ем

Зависит от СУБД и даже точной версии - везде свои встроенные строковые функции.

MySQL

Автор: macomics 20.01.24, 19:57
https://dev.mysql.com/doc/refman/8.0/en/str...function_substr

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)