Beliebt sind (oder besser gesagt, waren) diese Informationen bei Kreditangeboten aller Art. Einen monatlichen Zinssatz durch die Multiplikation * 12 in einen jährlichen umzurechnen, ist zur gleichen Zeit richtig und doch nicht. Auf diese Weise erhält man nur den Nominalzins. Der sogenannte Zinseszinseffekt kann aber für eine in der Regel weniger erfreuliche Überraschung sorgen. Berücksichtigt man diesen Effekt erhält man den Effektivzins. Dieser liegt umso höher, je mehr Zinszeitpunkte in einer Periode eintreten. Wie man jetzt genau von Nominalzins zum Effektivzins gelangt, ist zu einem guten Teil auch der Kreativität der Mathematiker überlassen. Da gibt es viele verschiedene Methoden, die z.B. mit der exakten Anzahl der Tage rechnen, oder vereinfachend mit 30/360er Regeln und, und... Ferner muß man überlegen, ob und inwieweit Bearbeitungskosten und sonstige Nebenkosten eingerechnet werden oder nicht. All dies interessiert aber hier an dieser Stelle nicht. Wir betrachtet hier einen einfachen Fall.
Beispiel: Die Firma "Wir nehmen's nicht so genau mit der Angabenpflicht unser Kreditangebote GmbH & Co. KG" wirbt mit dem Angebot für nur 1,55% Zinsen pro Monat all die kleinen Konsumwünsche zu erfüllen, auf die man sonst evtl. verzichten müßte. Ferner steht im Angebot eine Angabe zum jährlichen Zins iHv. 18,6%. Da man heutzutage (meint ;-) ) immer mehr repräsentieren zu müssen, um nicht ins gesellschaftliche Abseits, besuchen wir das Büro dieser Firma um einen Kreditvertrag über eine Summe von 10.000 € abzuschließen. Als es dann zur Unterschrift geht, haben wir das Geld zwar schon mental ausgegeben, zum Glück aber nichts an den Augen, als wir über eine Rückzahlungssumme von insgesamt 12.027,05 € in einem Jahr stolpern. Unserer Meinung nach sollte da ein Betrag ihV. 11.860 € stehen. Also über 167 € weniger oder etwas mehr als 1%. Wir verlassen empört das Büro und bauen uns folgendes SQL Statement, um nie wieder auf soetwas herein zufallen.
DECLARE @apr FLOAT
DECLARE @frequency FLOAT
SELECT @apr = 18.6, @frequency = 12
SELECT 100 * (POWER((1 + ((@apr/100)/@frequency)), @frequency)-1) AS EAR
EAR
-----------------------------------------------------
20.270504548765487
(1 row(s) affected)
Als Input wird der jährliche Nominalzins und die Anzahl der Zinszeitpunkte pro Periode angegeben. Da wir einen monatlichen Zins unterstellen, fallen also 12 Zinszeitpunkte in einem Jahr an. Wie bereits schon oben erwähnt, ist dieses Beispiel sehr einfach und kann beliebig variiert und kompliziert werden. Es sollte aber recht gut den Unterschied zwischen beiden Zinsangaben zeigen.
Wie könnte es aussehen, wenn man in einem so dynamischen Umfeld arbeitet, daß man selbst die mathematischen Berechnungsformeln nicht hart kodieren will...
Die Konvertierung von FLOAT Daten in CHAR oder VARCHAR im SQL Server 2000 kann unter Umständen für Überraschungen sorgen, die mehr oder weniger unangenehm sind. Mal angenommen wir finden einen gültigen Grund, warum wir FLOAT in VARCHAR umwandeln wollen und haben folgende Basisdaten
CREATE TABLE t1
(
Preis FLOAT
)
INSERT INTO t1 SELECT 0.99
UNION ALL SELECT 9.99
UNION ALL SELECT 99.99
UNION ALL SELECT 999.99
UNION ALL SELECT 9999.99
Die Abfrage, die diese Daten umwandeln soll, sieht folgendermaßen aus:
SELECT
CAST(Preis AS VARCHAR(10)) Preis
FROM t1
Preis
----------
0.99
9.99
99.99
999.99
9999.99
(5 row(s) affected)
So, kein Problem bisher. Nun betrachten wir einmal folgende Basisdaten:
INSERT INTO t1 SELECT 10000
UNION ALL SELECT 10000.49
UNION ALL SELECT 10000.5
UNION ALL SELECT 10000.51
UNION ALL SELECT 10000.99
SELECT
CAST(Preis AS VARCHAR(10)) Preis
FROM t1
Preis
----------
10000
10000.5
10000.5
10000.5
10001
(5 row(s) affected)
Es sieht ganz danach aus, als ob SQL Server 2000 ab 10000 intern eine Rundung vornimmt. Etwas in der Form.
SELECT
CAST(Preis AS VARCHAR(10)) Preis
, CONVERT(VARCHAR, Preis,0) FROM t1 Preis ---------- ------------------------------ 10000 10000 10000.5 10000.5 10000.5 10000.5 10000.5 10000.5 10001 10001 (5 row(s) affected)
So, wie kriegt man es nun hin, daß auch die Daten heraus kommen, die eingegeben wurden?
Eine Möglichkeit besteht darin, die Daten erst explizit in DECIMAL umzuwandeln und anschließend zurück in VARCHAR. Etwa so:
SELECT
CAST(Preis AS VARCHAR(10)) Preis
, CONVERT(VARCHAR, Preis,0)
, CAST(CAST(PREIS AS DECIMAL(8,2)) AS VARCHAR(20)) FROM t1 Preis ---------- ------------------------------ -------------------- 10000 10000 10000.00 10000.5 10000.5 10000.49 10000.5 10000.5 10000.50 10000.5 10000.5 10000.51 10001 10001 10000.99 (5 row(s) affected)
Eine weitere Möglichkeit wäre:
SELECT
CAST(Preis AS VARCHAR(10)) Preis
, CONVERT(VARCHAR, Preis,0)
, CAST(CAST(PREIS AS DECIMAL(8,2)) AS VARCHAR(20))
, LTRIM(RTRIM(STR(ROUND(Preis,2),10,2)))
FROM t1
Preis
---------- ------------------------------ -------------------- ----------
10000 10000 10000.00 10000.00
10000.5 10000.5 10000.49 10000.49
10000.5 10000.5 10000.50 10000.50
10000.5 10000.5 10000.51 10000.51
10001 10001 10000.99 10000.99
(5 row(s) affected)
Diese Methode geht nicht den Umweg über die explizite Konvertierung in einen anderen Datentypen. STR() wandelt FLOAT direkt um. Das RTRIM() ist zwar nicht zwingend notwendig, aber schadet auch nicht wirklich.
Warum zeigt SQL Server dieses Verhalten? Ehrlich gesagt, habe ich darauf keine Antwort. Eventuell könnte Single und Double Precision beim FLOAT Datentyp eine Rolle spielen, aber dies ist nur eine Vermutung. Falls jemand eine schlüssige Begründung für dieses Verhalten hat, würde ich micht freuen, diese zu hören.
Unter den diversen Aggregatfunktionen des T-SQL Arsenals nimmt COUNT() einen einmaligen Platz ein, weil dies die einzige Funtion ist, die "NULL-aware" ist. Das heißt, je nach Verwendung werden NULL Marker berücksichtigt oder nicht.
Liest man sich die Onlinehilfe von SQL Server durch und gelangt an das Thema ISNUMERIC(), erhält man den Eindruck, daß dies eine einfache, schnelle und sichere Methode ist, um zu überprüfen, ob ein gegebener Ausdruck in einen von SQL Server unterstützten numerischen Datentypen umgewandelt werden kann. Also, in einen der Datentypen: INTEGER, FLOAT (REAL), DECIMAL (NUMERIC) und MONEY.
Zunächst vielleicht erst einmal eine Erklärung, was hier überhaupt beschrieben werden soll. Mal angenommen, wir haben eine Tabelle, in der Kurse einer Aktie erfaßt werden. Der Einfachheithalber konzentrieren wir uns hier nur auf die entscheidenden Spalten Datum und Kurs und ignorieren alles weitere hier.
Schon mal darüber geärgert, daß es keine Möglichkeit gibt, die Spaltenüberschriften im BCP Utility mit auszugeben...?
Extrahieren von Teilstrings aus z.B. einer kommaseparierten Liste kann man überall nachlesen. Für Fragestellungen, bei denen es um die Extraktion von Teilstrings stets gleicher Länge geht, kann man aber auch einen anderen Lösungsansatz verwenden.