Rückgabe Sagen Sie SQL-Tabelle haben folgende:Erstellen effiziente MS SQL-Funktion gleichmäßig aufgeteilt Bereiche
-- create temp table
CREATE TABLE [tempNums]
(
id INT NOT NULL,
somedate datetime NULL
)
GO
mit einigen Daten (siehe unten für tempSplitStringToInts Definition):
-- with date
INSERT INTO [tempNums]
SELECT id, GETUTCDATE()
FROM [tempSplitStringToInts] ('1,2,3,5,10,100,101,102,103,233,1001,5002,5003,5005,5007,5010',',')
GO
-- without date
INSERT INTO [tempNums]
SELECT id, NULL
FROM [tempSplitStringToInts] ('6,7,8,150,151,152,153,433,2001,2002,2003,2005,3007,10010',',')
GO
Wie Sie bauen die BETTER/FASTER-Funktion, die die Anzahl der Bereiche annimmt, und ein Flag-Bit als Eingabe und gibt eine Tabelle mit Bereichswerten zurück?
So etwas wie dies funktioniert zum Beispiel, ist aber langsam für sehr große Tabellen:
-- create range function
CREATE FUNCTION [tempFnGetIdRanges]
(
@apps INT,
@has_date BIT
)
RETURNS @ret TABLE
(
RangeNum INT,
MinNum INT,
MaxNum INT
)
AS
BEGIN
DECLARE @i INT = 0;
DECLARE @count INT;
DECLARE @min INT;
DECLARE @max INT = 0;
IF @has_date = 1
BEGIN
SELECT @count = COUNT(id)
FROM [tempNums]
WHERE somedate IS NOT NULL
END
ELSE
BEGIN
SELECT @count = COUNT(id)
FROM [tempNums]
WHERE somedate IS NULL
END
DECLARE @top INT = @count/@apps;
WHILE @i<@apps
BEGIN
IF @[email protected]
BEGIN
-- on last get reminder
SET @top = @top + @apps
END
IF @has_date = 1
BEGIN
SELECT @min = MIN(id), @max = MAX(id)
FROM
(
SELECT TOP (@top) id
FROM [tempNums]
WHERE somedate IS NOT NULL
AND id > @max
ORDER BY id
) XX
END
ELSE
BEGIN
SELECT @min = MIN(id), @max = MAX(id)
FROM
(
SELECT TOP (@top) id
FROM [tempNums]
WHERE somedate IS NULL
AND id > @max
ORDER BY id
) XX
END
INSERT INTO @ret VALUES(@i, @min, @max)
SET @i = @i + 1;
CONTINUE
END
RETURN
END
GO
Also, wenn Sie laufen folgende:
SELECT * FROM [tempFnGetIdRanges](4, 0)
SELECT * FROM [tempFnGetIdRanges](4, 1)
Ergebnis für die erste Aussage:
RangeNum MinNum MaxNum
0 6 8
1 150 152
2 153 2001
3 2002 10010
Ergebnis für zweite Aussage:
RangeNum MinNum MaxNum
0 1 5
1 10 102
2 103 5002
3 5003 5010
Split-Funktion (als Referenz, aber nicht der Sinn dieser Frage):
-- create split string function
CREATE FUNCTION [tempSplitStringToInts] (@SourceString VARCHAR(MAX) , @delimeter VARCHAR(10))
RETURNS @IntList TABLE
(
id INT
)
AS
BEGIN
IF RIGHT(@SourceString, LEN(@delimeter))<> @delimeter
BEGIN
SELECT @SourceString = @SourceString + @delimeter
END
DECLARE @LocalStr VARCHAR(MAX)
DECLARE @start INT
DECLARE @end INT
SELECT @start = 1
SELECT @end = CHARINDEX (@delimeter , @SourceString , @start)
WHILE @end > 0
BEGIN
SELECT @LocalStr = SUBSTRING (@SourceString , @start , @end - @start)
IF LTRIM(RTRIM(@LocalStr)) <> ''
BEGIN
INSERT @IntList (id) VALUES (CAST(@LocalStr AS INT))
END
SELECT @start = @end + LEN(@delimeter)
SELECT @end = CHARINDEX (@delimeter , @SourceString , @start)
END
RETURN
END
GO
Wie gesagt ich dies funktioniert, aber es ist langsam für sehr große Tabellen. Gibt es eine bessere Möglichkeit,
tempFnGetIdRanges
Funktion schreiben? Etwas natives zu SQL? Ich verwendeMS SQL 2012
, wenn das relevant ist.
Sie haben hier bestimmte Leistungsanforderungen. Zuerst erstellen Sie Tabellenwertefunktionen, aber sie sind Tabellenfunktionen mit mehreren Anweisungen, die fast immer langsamer sind als selbst eine Skalarfunktion. Für den Leistungsvorteil einer Tabellenwertfunktion muss es eine einzelne Select-Anweisung und nichts mehr sein. Ich würde damit anfangen, den Splitter zu zerstören, den du hast. Es ist das Schlimmste des Schlimmsten. Es hat eine Schleife innerhalb einer Tabellenwertfunktion. Hier sind einige bessere Möglichkeiten dafür. http://sqlperformance.com/2012/07/t-sql-queries/split-strings –
Großartig, danke für den Kommentar. Ich schaue mir bessere Splitterfunktionen an. – CrnaStena
Was macht diese Hauptfunktion?Wenn HasDate = 1 ist, wird es nur in Gruppen aufgeteilt, aber wenn es null ist, macht die Ausgabe für mich keinen Sinn. Was ist die Logik dort? –