Napadlo vás někdy, že SQL může být v matematice špatně? Zní to šíleně. Ale pokud jste použili datový typ SQL FLOAT, možná jste narazili na problémy, které se vám chystám ukázat.
Zvaž toto. 0,1 + 0,2 by mělo být 0,3, že? Ale zkontrolujte to pomocí datového typu SQL FLOAT.
DECLARE @f1 FLOAT = 0.1
DECLARE @f2 FLOAT = 0.2
SELECT CASE WHEN @f1 + @f2 = .3 THEN 1 ELSE 0 END
Správný výsledek je 1. Ale zkontrolujte obrázek 1.
Mám teď vaši pozornost? To doufám. Je docela děsivé záviset na systému, který nám nedá správnou matematiku. Ale tento článek vám pomůže se tomu vyhnout.
Je tu nějaká práce. Musíme začít od toho, o čem je datový typ FLOAT.
Co je datový typ SQL FLOAT?
SQL FLOAT datový typ je přibližný číselný datový typ používaný pro čísla s plovoucí desetinnou čárkou. Mohou ukládat velmi velká nebo velmi malá čísla. Používají se také pro výpočty, které vyžadují rychlé zpracování.
To vše přichází za cenu ztráty přesnosti. Dále nemůžete říci, kde bude po výpočtu umístěna desetinná čárka – pluje . Mezitím přesné číslice jako DECIMAL budou mít pevnou pozici desetinné čárky.
Jak deklarujete datový typ SQL FLOAT
Syntaxe je FLOAT[(n)], kde n je počet bitů použitých k uložení mantisy čísla s plovoucí desetinnou čárkou ve vědecké notaci. To také určuje přesnost a velikost úložiště. Možné hodnoty pro n jsou mezi 1 až 53. Všimněte si, že n je volitelné.
Zde je příklad:
DECLARE @floatValue1 FLOAT; -- Float variable without the number of bits
DECLARE @floatValue2 FLOAT(3) -- Float variable with 3 bits
Pokud nezadáte n , výchozí hodnota je 53. To je také maximální hodnota. Dále FLOAT(53) je číslo s plovoucí desetinnou čárkou s dvojitou přesností nebo binární64. Kromě použití FLOAT(53) jej můžete také deklarovat jako DOUBLE PRECISION.
Následující 3 deklarace jsou funkčně ekvivalentní:
DECLARE @double1 FLOAT(53);
DECLARE @double2 FLOAT;
DECLARE @double3 DOUBLE PRECISION;
Tabulka ukazuje počet bitů a odpovídající velikost úložiště.
Hodnota n | Velikost úložiště |
1 až 24 | 4 bajty |
25 až 53 | 8 bajtů |
Je SQL FLOAT a REAL totéž?
REAL je také FLOAT(24). Označuje se také jako single-precision nebo binární32.
Proč je důležité toto vědět
Pokud víte, že se jedná o přibližné číslo, nebudete ho používat pro výpočty, které vyžadují přesnost. Zajímá vás také úložiště a paměť? Pokud nepotřebujete příliš velké nebo příliš malé hodnoty, použijte REAL nebo FLOAT(24).
Jaké jsou rozdíly mezi FLOAT a DECIMAL?
FLOAT je přibližné číslo. DECIMAL je přesné číslo. Zde je souhrn rozdílů v tabulce:
PLOVÁVÁNÍ | DECIMÁLNÍ | |
Desetinná čárka | Lze umístit kdekoli v číslici | Pevná pozice |
Maximální limit | 38 číslic nebo 99,999,999,999,999,999,999,999,999,999,999,999,999 | FLOAT(53) má maximální rozsah 1,79E+308 nebo 179 následovaný 306 nulami |
Úložiště | Maximálně 8 bajtů | Maximálně 17 bajtů |
Výpočetní výsledek | Přibližné | Přesně |
Kontrola porovnání | Nepoužívejte =nebo <>. Vyhněte se zaokrouhlování | Operátory=nebo <>. Dobré pro zaokrouhlení |
Na obrázku 1 jste již viděli, jak může mít výpočet čísla FLOAT podivné výsledky. Pokud změníte typ dat na DECIMAL takto:
DECLARE @d1 DECIMAL(2,1) = 0.1
DECLARE @d2 DECIMAL(2,1) = 0.2
SELECT CASE WHEN @d1 + @d2 = 0.3 THEN 1 ELSE 0 END
Výsledek bude správný.
Problémem je také použití operátoru nerovnosti. Podívejte se na smyčku níže.
DECLARE @floatValue FLOAT(1) = 0.0
WHILE @floatValue <> 5.0
BEGIN
PRINT @floatValue;
SET @floatValue += 0.1;
END
Co myslíš? Viz obrázek 2 níže.
Výložník! Nekonečná smyčka! Podmínka nerovnosti bude vždy pravdivá. Logickou volbou je tedy změnit typ na DECIMAL.
DECLARE @decimalValue DECIMAL(2,1) = 0.0
WHILE @decimalValue <> 5.0
BEGIN
PRINT @decimalValue;
SET @decimalValue += 0.1;
END
Výše uvedený kód se určitě zastaví, když @decimalValue se rovná 5,0. Přesvědčte se sami na obrázku 3 níže.
Pěkný! Ale pokud stále trváte na FLOAT, bude to fungovat dobře bez nekonečné smyčky.
DECLARE @floatValue FLOAT(1) = 0.0
WHILE @floatValue < 5.0
BEGIN
PRINT @floatValue;
SET @floatValue += 0.1;
END
Mezitím je také vypnuto zaokrouhlování. Zvažte následující:
DECLARE @value FLOAT(2) = 1.15
SELECT ROUND(@value, 1) -- This will result to 1.1
Místo 1.20 je výsledkem kódu 1.1. Ale pokud použijete DECIMAL, výsledek bude správný.
DECLARE @value DECIMAL(3,2) = 1.15
SELECT ROUND(@value, 1) -- This will result in 1.2 or 1.20
Když je FLOAT správně a DECIMAL není
Nejsou přesná čísla vždy tak přesná? K reprodukci tohoto problému použijeme výpočet a poté jej obrátíme. Nejprve si připravme data.
CREATE TABLE ExactNumerics1
(
fixed1 DECIMAL(8,4),
fixed2 DECIMAL(8,4),
fixed3 DECIMAL(8,4),
calcValue1 AS fixed3 / fixed1 * fixed2
)
GO
INSERT INTO ExactNumerics1
(fixed1,fixed2,fixed3)
VALUES
(54,0.03,1*54/0.03)
Výše uvedená tabulka použije pevné hodnoty pro první 2 sloupce. Ve třetím sloupci bude výpočet. Nakonec čtvrtý, což je počítaný sloupec, provede opačný výpočet. Správný výsledek ve vypočítaném sloupci by měl být 1.
Nyní, abychom to porovnali s FLOAT, vytvořte podobnou tabulku a data.
CREATE TABLE ApproxNumerics1
(
float1 FLOAT(2),
float2 FLOAT(2),
float3 FLOAT(2),
calcValue1 AS float3 / float1 * float2
)
INSERT INTO ApproxNumerics1
(float1, float2, float3)
VALUES
(54,0.03,1*54/0.03)
Pojďme se zeptat.
SELECT * FROM ApproxNumerics1
SELECT * FROM ExactNumerics1
Výsledky? Podívejte se na obrázek 4.
Co se tu stalo? FLOAT to pochopil správně, ale DECIMAL ne. Něco se pokazilo.
IMPLICITNÍ KONVERZE TO ZNOVU DĚLÁ
K implicitní konverzi dochází, protože SQL je shovívavý. Když jsou ve výpočtu použity různé typy dat, SQL Server se je pokusí převést pomocí implicitní konverze za našimi zády.
Opravdu došlo ke konverzi? Kromě toho každý sloupec v ExactNumerics1 tabulka je DESETINNÁ.
Podívejme se na strukturu tabulky ExactNumerics1 tabulka v SQL Server Management Studio:
Všimněte si oblasti s červeným rámečkem na obrázku 3. Vypočítaný sloupec je DECIMAL(30,17), nikoli DECIMAL(8,4). Podle oficiální dokumentace 2 DECIMÁLNÍ sloupce s různou přesností a měřítkem jsou 2 různé datové typy . Přesvědčte se sami zde. Kvůli rozdílu je nutná konverze. Do hry tedy vstupuje implicitní konverze.
Co když se liší a došlo k implicitní konverzi?
Opět platí, že na základě oficiální dokumentace může během implicitní konverze dojít ke ztrátě přesnosti nebo měřítka . Je tedy vyžadován explicitní CAST. Všimněte si datového typu DECIMAL v převodní tabulce v tomto odkazu.
Tady se právě stala nějaká ztráta. Pokud je vypočítaný sloupec také DECIMAL(8,4), implicitní převod nenastane.
Chcete-li se vyhnout implicitní konverzi, postupujte podle oficiální dokumentace. Struktura tabulky by měla být tato:
CREATE TABLE ExactNumerics2
(
fixed1 DECIMAL(8,4),
fixed2 DECIMAL(8,4),
fixed3 DECIMAL(8,4),
calcValue1 AS CAST(fixed3 / fixed1 * fixed2 AS DECIMAL(8,4)) -- the explicit CAST
)
Explicitní CAST ve vypočítaném sloupci zajišťuje, že datové typy jsou konzistentní. Pokud také dodržíme tuto strukturu a vložíme stejná data, bude výsledek správný. Podívejte se na nový výstup na obrázku 6 níže.
Přesná čísla nakonec nebudou přesná, pokud k implicitnímu převodu dojde mezi 2 nebo více DECIMAL hodnotami.
Proč je důležité toto vědět
Poskytuje vám představu o tom, co potřebujete pro své tabulky a proměnné. Navíc implicitní převod může způsobit, že i přesná čísla se zblázní. Takže explicitně definujte přesnost a měřítko a buďte s nimi ve svých výpočtech konzistentní.
Mám používat SQL FLOAT pro finanční data?
Při výpočtu procent v každé části koláčového grafu by součet měl být 100 %. Součty v souhrnných a podrobných zprávách by také měly být konzistentní. Pokud je přesnost výsledků klíčová, přibližný datový typ, jako je FLOAT, tuto práci nesplní. Logická volba je DECIMAL.
Ale zůstává otázka.
Kdy byste měli používat FLOAT?
Použijte FLOAT pro data, která vyžadují astronomické hodnoty, jako jsou vzdálenosti mezi galaxiemi. Mezitím bude datový typ DECIMAL trpět aritmetickým přetečením tohoto typu dat. Drobné hodnoty, jako je průměr atomového jádra, se také hodí pomocí FLOAT. Z FLOAT mohou těžit i vědecká data a další hodnoty, které nevyžadují přesnost.
Proč je důležité toto vědět
Neříkáme, že FLOAT je špatný a DECIMAL je dobrý nebo naopak. Znalost správných případů použití pro každý z nich vám a vašim uživatelům poskytne zamýšlené výsledky. A pak znovu, chcete, aby byli vaši uživatelé šťastní, že?
Závěr
Na konci dne chceme všichni dělat svou práci a být v ní dobří. Matematika bude vždy součástí naší práce. A znalost správných číselných datových typů nám také pomůže se s tím vypořádat. Není to těžké, pokud víte, co děláte.
Doufám, že vám tento článek pomohl vyhnout se podivné matematice na serveru SQL.
Chceš ještě něco dodat? Pak nám dejte vědět v sekci Komentáře. Sdílejte to také na svých oblíbených platformách sociálních médií.