SQL - špatný výsledek při dělení decimal   zodpovězená otázka

SQL

Zdravím, narazil jsem na jeden problém který mi připadá podivný. Zřejmě špatně používám datový typ decimal.

DECLARE @value DECIMAL(18,5)
SET @value=ROUND(4/12,5)

SELECT @value

V tomto kódu bych čekal, že se mi vydělí 4/12 a výsledek se mi potom zaokrouhlí přes funkci round na 5 desetinných míst. Místo toho mi pořád vychází nula. Pokud je výsledek větší než 1 tak se mi oříznou desetinná místa a zbydou nuly. Mohl by mi prosím někdo říct co dělám špatně?

Jinak jsem pochopil, že v deklaraci decimal druhé čislo znamená počet desetinných míst které budou zobrazeny a první číslo je přesnost. Tu jsem ale moc nepochopil, takže jsem nechal nastavenou defaultní hodnotu. Možna že je problém právě v té přesnosti?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Tak jsem zjistil, že pokud dám 12.0/4 tak už je výsledek správný. Ale stejně mi to příjde divné.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Problém bude v samotném dělení - dělíte celá čísla, výsledek je celé číslo. SQL nebere ohled na typ, do kterého hodnotu vkládáte (snad logicky), ale evidentně respektuje typy v dělení dané zápisem. Je tedy třeba zápisem 12.0/4 sdělit, že se nejedná o celé číslo, nebo hodnoty předem nadefinovat anebo je konvertovat.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Nemáte tam překlep? ROUND(4/12,5) nebo ROUND(12/4,5)???

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Není tam překlep, právě že například 4/12 vrátí nulu.

Měl jsem právě zato, že SQL respektuje datový typ který mu nastavím. Stejně to funguje ve VB. Podle toho jestli je proměnná typu integer nebo double je výsledek buď bez desetinných čísel nebo s nima.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Podle toho jestli je proměnná typu integer nebo double je výsledek buď bez desetinných čísel nebo s nima.

No pozor, tam je to trochu jinak. Problém je v tom, jak je definován operátor /, operátor je totiž vlastně úplně nornální funkce, která na vstupu dostane dva parametry nějakého typu a vrátí hodnotu nějakého typu. V C# a dle tohoto příkladu i SQL je prostě operátor / definován jako funkce, která bere 2 integery a vrací integer. Také je tam definován operátor nad desetinnými čísly a vrací desetinné číslo.

Ve VB.NET operátor / vrací vždy desetinné číslo, ať už do něj jdou integery nebo ne. VB.NET pořád rozlišuje mezi datovými typy a je typově striktní, ale má definovanou i automatickou konverzi z double na integer. Tím pádem se to chová tak, jak se to chová. Výsledkem delění operátorem / je vždy Double, ale ten se dá přiřadit i do Integeru bez nutného přetypování jako v C#.

Asi o tom napíšu .NET tip, je to docela zajímavé téma.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Díky za vysvětlení.

Abych to tedy shrnul, tak v SQL (alespon na MS SQL serveru, jak se to chová jinde nevím) pokud chci aby výsledek bylo desetinné číslo, musím použít odpovídající datový typ a ještě při zadávání hodnot zadat desetinná místa např. (4.0/12)

A pokud bych potřeboval počítat s číslama které pošlu na server přes parametry tak to musím ošetřit už v klientské aplikaci a posílat to rovnou s desetinnýma místama?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pošlete tam prostě hodnotu Double. Pokud do kódu (ať už v SQL nebo ve VB.NET) napíšete 15, je to hodnota typu Integer. Pokud napíšete 15.0, je to hodnota typu Double. Ničím jiným to není.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ok ještě jednou díky

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Typ výsledku ve je tedy závislý na použitém aritmetické operátoru (liší se / * - +) a typem výrazů, které do operace vstupují. Myslím, že ve VB typ výsledku není tak jednoznačný ("Ve VB.NET operátor / vrací vždy desetinné číslo, ať už do něj jdou integery nebo ne. ") a navíc bychom museli studovat co v konkrítních případech provede automatické přetypování. U SQL chování známe jen podle praktické zkušenosti ("... a dle tohoto příkladu i SQL). Jistotu budeme mít, když nebudeme operace typu r = 4/12 používat a když, tak se jistit pro přesnější výsledek s r = 4.0/12. Jistější (bez zkoumání a hádání) je hodnoty předem nadefinovat a použít r = a/b anebo hodnoty konvertovat.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Omlouvám se. Jako nevěřící Tomáš (zde spíš Tomášovi) jsem zkusil VB 6 i .NET a "Ve VB.NET operátor / vrací vždy desetinné číslo, ať už do něj jdou integery nebo ne. " je svatá pravda!

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback