Към съдържанието
wannacode

Сметки в заявката

Накратко: В SELECT можеш да смяташ с колоните (+, -, *, /) за всеки ред и да закръгляш с ROUND, но в SQLite, PostgreSQL и SQL Server делението на две цели числа отрязва дробната част.

Проблем

Колко струва този ред?

Счетоводството иска за всеки ред от поръчка колко струва: количеството по цената. В таблицата order_items има само двете числа:

SQLбаза: магазин

В поръчка 3 има ябълки, 4 по 2,10 €, и прах за пране, 3 по 12,50 €. Да смяташ на ръка за 152 реда не е работа за човек. А да пазиш сумата в още една колона значи да я поддържаш вярна при всяка промяна.

Идеята

Колона, която се смята

В SELECT освен колони може да пишеш и изрази: сметки с колоните. Базата ги пресмята за всеки ред:

SQLбаза: магазин

Знаците са +, -, *, / и % (остатък при деление). Името на сметнатата колона е самият израз, затова ѝ даваш кратко име с AS. Таблицата не се променя: сметката е само в резултата.

По псевдонима може и да подредиш. Петте най-скъпи реда от всички поръчки:

SQLбаза: магазин

Изразът може и без таблица. Тогава SELECT пресмята веднъж, като калкулатор. Умножението е преди събирането, а скобите сменят реда:

SQLбаза: магазин

Пробвай

Цената с ДДС

Цените в базата са без ДДС. Покажи името, цената и цената с 20% ДДС в колона with_vat.

SQLбаза: магазин

Виж го

Оценката в проценти

Сайтът иска да показва оценките от 1 до 5 като проценти: 5 е 100%, 4 е 80%. Пусни:

SQLбаза: магазин
1. Отзивът с оценка 4 излезе с 0%. Защо?

Това е целочислено деление. Когато и двете числа са цели, резултатът също е цял:

SQLбаза: магазин

Щом едното число е дробно (2.0) или е превърнато в дробно с CAST(… AS REAL), и делението е дробно. За процентите е достатъчно да умножиш първо, по 100.0:

SQLбаза: магазин

При price този капан го няма: цената е дробно число (REAL). Пази се при колоните с цели числа, като rating, quantity и stock.

По-точно, за любопитните

PostgreSQL и SQL Server делят целите числа по същия начин: 5 / 2 е 2. MySQL прави обратното: там 5 / 2 е 2.5000, а за целочислено деление има DIV. Делението на нула в SQLite дава NULL, а в PostgreSQL е грешка.

Идеята

ROUND: до цент

Промоция: −15% на млечните. Новата цена е 85% от старата:

SQLбаза: магазин

Кисело мляко за 0,935 € не може да се плати. ROUND(x, 2) закръгля до две цифри след точката, тоест до цент. ROUND(x) закръгля до цяло число.

Погледни сиренето: 6,715 стана 6,71, а не 6,72. Защо, виж отдолу.

По-точно, за любопитните

Дробните числа в компютъра се пазят в двоична система, а там 0,1 няма точен запис, както 1/3 няма точен запис с десетични цифри. Затова:

SQLбаза: магазин

На екрана е 0,3, но на сравнението базата казва „не“ (0). printf с %!.20f показва какво е записано наистина. Същото е със сиренето: 7,9 × 0,85 в паметта е 6,71499…, и ROUND честно го закръгля надолу.

Затова в истинските системи парите не се пазят като REAL. Пазят се в цели центове (1,20 € е 120), или в тип за точни десетични числа: NUMERIC(10, 2) или DECIMAL(10, 2) в PostgreSQL, MySQL и SQL Server. В SQLite такъв тип няма, затова там се ползват центове:

SQLбаза: магазин

С центове 790 × 85 е точно 67 150, а делението на 100 дава 671,5 цента, които се закръглят до 672, тоест 6,72 €.

Пробвай

Промоцията

Покажи името, цената и промоционалната цена на всички продукти. Промоционалната е price * 0.85, закръглена до цент, в колона sale_price.

SQLбаза: магазин

Упражнение

Две задачи

1. Застрахователят пита колко струва стоката в склада. Покажи петте продукта с най-голяма стойност на наличността (цена по наличност), най-голямата първа. Подаръчната карта не е стока на рафта: остави само продуктите с категория.

Име, наличност и stock_value, петте най-големи:

SQLбаза: магазин

2. Стоката пристига в кашони по 12 бройки. За всеки продукт с категория, който е в наличност, покажи колко пълни кашона са (boxes) и колко бройки остават извън тях (loose).

Име, наличност, boxes и loose:

SQLбаза: магазин

Тест

Провери се

1. Какво връща SELECT 7 / 2;?
2. Променя ли SELECT price * 1.2 AS with_vat FROM products; цените в таблицата?
3. Кое подрежда редовете на поръчките по стойност, най-голямата първа?
4. Какво дава ROUND(2.345, 1)?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·