Nur drei signifikante Stellen im Ergebnis erzwingen

Hallo zusammen,

Gibt es eine Möglichkeit, im Ergebnis von Abfragen immer nur drei signifikante Stellen auszugeben?

z.B.
1,45456 --> 1,46
1.657.456.456,8934 --> 1.660.000.000,000
0,1 --> 0,100

etc.



grüße!

In Mathe habe ich mal folgendes gelernt:

1.4567 * 1000, Nachkommastellen abschneiden, durch 1000 dividieren

Das umgesetzt in SQL sieht ungefähr so aus:

SELECT (1.456754 * 1000)::INT::FLOAT / 1000;

Da kann man jetzt statt den Casts noch passend ROUND() oder FLOOR() einstreuen.

danke!

was meinst du mit casts? sorry bin newbie…

Eine Typumwandlung. So ist z.B. ‘123’ ein String. Doch schaue selber:

test=*# select '123';
 ?column?
----------
 123
(1 row)

test=*# select cast('123' as int);
 int4
------
  123
(1 row)

test=*# select '123'::int;
 int4
------
  123
(1 row)

Das cast(…) ist SQL.Spec, das …int ist eine Vereinfachung von PG und nicht portabel.

Andreas

Gähn

select trunc(x, -log(x)::int + 2)

Demo

WITH vals(x) AS (
    VALUES(123456789), (123.456), (1.23456), (0.0000123456)
)
SELECT trunc(x, -log(x)::int + 2) FROM vals
------------------------------------------------
123000000
123
1.23
0.0000123



Also, symbiont, ich weiß zwar nicht, wo du im Matheunterricht warst, aber die Verwendung von log(x) an dieser Stelle ist eine große Verschwendung.

warum soll das verschwendung sein … log(x) kann ein prozessor im schlaf (seit es FPUs gibt - seit 10 jahren oder laenger?)

das ist 1. um fantastillionen % effizienter
und 2. funktioniert es korrekt

anders als dieses dividiere und gecaste in strings was ohnehin nicht zum ergebnis fuehrt

aber ist ja auch egal … wo du in mathe warst hast ja bereits demonstriert

ein alter x87er macht das so

; LOG(x)-       Computes the base 10 logarithm of x.
[font=Courier New][size=84];               Usual range for x (>0).
;
;       LOG(x) = lg(x)/lg(10).

log             proc    near
                fld1
                fxch
                fyl2x           ;Compute 1*lg(x).
                fldl2t          ;Load lg(10).
                fdiv            ;Compute lg(x)/lg(10).
                ret
log             endp
[/size][/font]

ein moderner hat dafuer wahrscheinlich einen opcode - bin mir da aber nicht sicher, was den “wahnsinns aufwand” nochmal etwas mehr als halbieren wuerde

und wie wir sehen muss da noch ein abs( … ) umd das x im log(…)
weil: select log(-1) => FEHLER: Logarithmus negativer Zahlen kann nicht ermittelt werden
SQL Status:2201E


also:

select trunc(x, -log(abs(x))::int + 2)

und es fehlt noch ein + 0.5

select trunc(x, (-log(abs(x)) + 0.5)::int + 2)

oder man benutzt round() …

Ja, schön, was dein Assembler alles kann - wenn man mal bis dorthin kommt. Die ganze log() Berechnung, nur um die Anzahl Stellen zu ermitteln, ist trotzdem recht sinnlos und verkompliziert das ganze nur unnötig.

Eine Multiplikation mit 1000 kann die gleiche FPU, die auch für dein log() bemüht wird, nur ist das halt einfacher zu lesen und weniger Code und Rechenoperationen. Das “gecaste” kann mit ROUND() oder FLOOR() erledigt werden, das sagte ich aber schon in meinem ersten Posting.

nur dass dir deine multiplikation mit 1000 rein garnichts bringt … deine “loesung” ist schlichtweg falsch

und immernoch ist da kein “ganze log() Berechnung” … da ist nix aufwendiges dabei …

die anwendung des log(x) ist schlicht und ergreifend die richtige loesung der gestellten aufgabe

aber egal …

Was willst du eigentlich? Mein Beispiel gibt 3 Nachkommastellen aus, also was passt dir daran nicht?

  1. versuch
WITH vals(x) AS (
    VALUES(123456789), (123.456), (1.23456), (0.000010999789)
)
SELECT 
  trunc(x, -(log(x) + 0.5)::int + 3) as symbiont, 
  (x * 1000)::[B]INT[/B]::FLOAT / 1000 as ads
FROM vals
-------------------------------------------
FEHLER: integer ist außerhalb des gültigen Bereichs
SQL Status:22003

ok 2. versuch

WITH vals(x) AS (
    VALUES(123456789), (123.456), (1.23456), (0.000010999789)
)
SELECT 
  trunc(x, -(log(x) + 0.5)::int + 3) as symbiont, 
   (x * 1000)::[B]BIGINT[/B]::FLOAT / 1000 as ads
FROM vals
---------------------------------------
[U]symbiont;    ads[/U]
123000000;   123456789 (falsch)
123;         123.456 (falsch)
1.23;        1.235 (falsch)
0.0000109;   0 (falsch)

Ich versuch auch mal was, und zwar zu schlichten.

Meine Vermutung ist, ihr beide redet aneinander vorbei. ‘Signifikante Stellen’, darunter versteht man eigentlich Nachkommastellen. Zumindest war das meine erste Interpretation, und offensichtlich auch die von ads.

Der Ursprungsposter meinte aber was anderes, Du hast es richtig erkannt.

So what? Peace!

Andreas

ich habe kein problem damit wenn jemand was falsch versteht

ich habe nur die gelegenheit genutzt um auch mal zu gähnen :wink:

ein mathegenie bin ich auch nicht … aber ich weiss was haltlose behauptungen sind @ log … und wenns nur um die signifikanten nach dem komma waeren dafuer hat das gute postgres ja neben
dem trunc(x) das
trunc(x, n) -> n = 3

WITH vals(x) AS (
    VALUES(123456789), (123.456), (1.23456), (0.000010999789)
)
SELECT 
  trunc(x, 3) as akretschmer
FROM vals
--------------
123456789.000
123.456
1.234
0.000

also weiter im programm

ach ja - der vollstaendigkeit halber muss man noch erwaehnen, dass log(0) nicht definiert ist …

select log(0)

FEHLER: Logarithmus von null kann nicht ermittelt werden
SQL Status:2201E

Stimmt. Ich bin von Nachkommastellen ausgegangen und habe das Eingangsposting falsch gelesen.

symbiont: du hast Recht, für Nachkommastellen gibt es auch trunc().
Für die gegebene Aufgabenstellung ist die Berechnung eine gute Lösung.

das naechste mal dürft ihr wieder gähnen …

mein naechter irrtum kommt bestimmt

… das trunc(x, n) hab ich heute auch erst entdeckt … schoen ist, dass n offenbar auch negativ sein darf - also es auch vor dem komma genauigkeiten abschneiden kann …

Also danke erstmal für die Anstrengungen. Symbiont hat den für mich passenden,richtigen Lösungsweg gefunden.
Allerdings krieg ich bei x= 0 das problem: ERROR: cannot take logarithm of zero.

Eigentlich klar. nur hab ich halt manche Felder mit 0 drinne. Deshalb soll aber nicht das ganze skript abstürzen. Wie kann ich das umgehen, also bei x=0 keine berechnung machen?

Irgendwie ein CASE einbauen.

CASE wirkt.

Jetzt hab ich folgendes Problem: ERROR: integer out of range.

Wie bekomme ich das ganze auch mit großen ints hin?

@symbiont:
in den meisten Fällen funktioniert das mit log, nur warum wird z.B. aus
21.2 --> 21

21.2 hat doch schon drei signifikante Stellen…