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!
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?
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
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…