Dies ist die Adaption der Excel Funktion GGT().
CREATE FUNCTION dbo.ggt(@zahl1 int, @zahl2 int)
RETURNS INT
AS
BEGIN
DECLARE @zahl3 INT
SET @zahl3=1
WHILE (@zahl3 <> 0)
BEGIN
SET @zahl3=@zahl1 % @zahl2
SET @zahl1=@zahl2
SET @zahl2=@zahl3
END
RETURN @zahl1
END
GO
SELECT dbo.ggt(24,36)
DROP FUNCTION dbo.ggt
-----------
12
(1 row(s) affected)
Dynamisches SQL kann nicht innerhalb einer Funktion ausgeführt werden. Genausowenig können Stored Procedures aufgerufen werden. Der einzige Workaround hier ist, eine andere Logik anzuwenden, um um den dynamischen Teil herumzukommen. So führt z.B. folgendes zu einem Fehler:
Eine beliebte Frage mit unzähligen Antworten. Meine Lieblingsantwort darauf ist, dies in der Präsentationsschicht seiner Anwendung zu machen. IMHO ist dies Aufgabe des Clients, nicht des Servers. Wenn es aber unbedingt in T-SQL gemacht werden soll, kann man folgendes machen:
USE PUBS
GO
SELECT
(
SELECT COUNT(*)
FROM Authors
WHERE au_id <= A.au_id
) AS Lfd_Nr
, au_lname, au_fname
FROM
Authors AS A
ORDER BY
Lfd_Nr
GO
Lfd_Nr au_lname au_fname
----------- ---------------------------------------- --------------------
1 Hello World Johnson
2 Green Marjorie
3 Carson Cheryl
4 O'Leary Michael
5 Straight Dean
6 Smith Meander
7 Bennet Abraham
8 Dull Ann
9 Gringlesby Burt
10 Locksley Charlene
11 Greene Morningstar
12 Blotchet-Halls Reginald
13 Yokomoto Akiko
14 del Castillo Innes
15 DeFrance Michel
16 Stringer Dirk
17 MacFeather Stearns
18 Karsen Livia
19 Panteley Sylvia
20 Hunter Sheryl
21 McBadden Heather
22 Ringer Anne
23 Ringer Albert
(23 row(s) affected)
Bei umfangreichen Resultsets kann die obige Methode schon mal einige Zeit in Anspruch nehmen. Ist also nur bedingt empfehlenswert. Eine Alternative ist vielleicht die Verwendung der IDENTITY Funktion zusammen mit einer temporären Tabelle, so wie hier:
SELECT
IDENTITY(INT,1,1) AS Lfd_Nr
, au_lname
, au_fname
INTO #authors
FROM authors
ORDER BY au_id
SELECT *
FROM #authors
ORDER BY Lfd_Nr
DROP TABLE #authors
Lfd_Nr au_lname au_fname
----------- ---------------------------------------- --------------------
1 Hello World Johnson
2 Green Marjorie
3 Carson Cheryl
4 O'Leary Michael
5 Straight Dean
6 Smith Meander
7 Bennet Abraham
8 Dull Ann
9 Gringlesby Burt
10 Locksley Charlene
11 Greene Morningstar
12 Blotchet-Halls Reginald
13 Yokomoto Akiko
14 del Castillo Innes
15 DeFrance Michel
16 Stringer Dirk
17 MacFeather Stearns
18 Karsen Livia
19 Panteley Sylvia
20 Hunter Sheryl
21 McBadden Heather
22 Ringer Anne
23 Ringer Albert
(23 row(s) affected)
In SQL Server 2005 ist dies übrigens einfacher durch die Implementierung von ROW_NUMBER().
USE PUBS GO SET NOCOUNT ON CREATE TABLE #TableSpace ( Name char(20) ,RowCnt int ,Reserved varchar(15) ,Data varchar(15) ,Index_Size varchar(15) ,Unused varchar(15) ) DECLARE @Table sysname DECLARE TableCur CURSOR FOR SELECT Table_Name FROM INFORMATION_SCHEMA.Tables WHERE Table_Type = 'BASE TABLE' AND OBJECTPROPERTY(OBJECT_ID(Table_Name),'IsMSShipped') = 0 OPEN TableCur FETCH NEXT FROM TableCur INTO @Table WHILE @@FETCH_STATUS = 0 BEGIN INSERT #TableSpace EXEC sp_spaceused @Table FETCH NEXT FROM TableCur INTO @Table END CLOSE TableCur DEALLOCATE TableCur SELECT * FROM #TableSpace DROP TABLE #TableSpace SET NOCOUNT OFF Name RowCnt Reserved Data Index_Size Unused -------------------- ----------- --------------- --------------- --------------- --------------- __tmpTBLCOL 131 80 KB 16 KB 8 KB 56 KB authors 23 40 KB 8 KB 32 KB 0 KB discounts 3 16 KB 8 KB 8 KB 0 KB dup_authors 40 80 KB 16 KB 8 KB 56 KB employee 43 40 KB 8 KB 32 KB 0 KB jobs 14 24 KB 8 KB 16 KB 0 KB max_t 4 16 KB 8 KB 8 KB 0 KB median 8 16 KB 8 KB 8 KB 0 KB pub_info 8 160 KB 120 KB 16 KB 24 KB publishers 8 24 KB 8 KB 16 KB 0 KB roysched 86 32 KB 8 KB 24 KB 0 KB sales 21 56 KB 8 KB 48 KB 0 KB silly_one 0 0 KB 0 KB 0 KB 0 KB stores 6 24 KB 8 KB 16 KB 0 KB tableCounts 15 16 KB 8 KB 8 KB 0 KB titleauthor 25 56 KB 8 KB 48 KB 0 KB titles 18 40 KB 8 KB 32 KB 0 KB Trace_Table_Name 0 0 KB 0 KB 0 KB 0 KB vals 127 24 KB 8 KB 16 KB 0 KB x 2 16 KB 8 KB 8 KB 0 KB
Danke an Jonathan van Houtte für das Originalskript.
Um sicherzustellen, dass RowCnt aktuell ist, sollte man vorher
DBCC UPDATEUSAGE(0) WITH COUNT_ROWS
ausführen.
CREATE FUNCTION dbo.fakultät(@n DECIMAL(38,0))
RETURNS DECIMAL(38,0)
AS
BEGIN
DECLARE @tmp DECIMAL(38,0)
IF (@n <= 1)
SELECT @tmp = 1
ELSE
SELECT @tmp = @n * dbo.fakultät(@n - 1)
RETURN @tmp
END
GO
SELECT dbo.fakultät(10)
DROP FUNCTION dbo.fakultät
----------------------------------------
3628800
(1 row(s) affected)
Spielt man dieses Spielchen weiter, wird man feststellen, dass man bei Zahlen grösser als 32, folgende Meldung erhält:
Server: Nachr.-Nr. 217, Schweregrad 16, Status 1, Prozedur fakultät, Zeile 9
Die maximale Schachtelungsebene für .... (Limit ist 32).
Man wird auch feststellen, dass bei Input von 32 eine Abweichung zu Excel existiert.
DECLARE @x1 FLOAT
DECLARE @x2 FLOAT
DECLARE @y1 FLOAT
DECLARE @y2 FLOAT
SELECT @x1 = 1, @x2 = 2, @y1 = 1, @y2 = 2
SELECT (@y2-@y1)/(@x2-@x1)
-----------------------------------------------------
1.0
(1 row(s) affected)
Oder als UDF
CREATE FUNCTION dbo.steigung(@y1 FLOAT,@y2 FLOAT, @x1 FLOAT, @x2 FLOAT)
RETURNS FLOAT
AS
BEGIN
RETURN (@y2-@y1)/(@x2-@x1)
END
GO
SELECT dbo.steigung(1,2,1,2)
DROP FUNCTION dbo.steigung
-----------------------------------------------------
1.0
(1 row(s) affected)