2010-06-09 6 views
7

Wir haben eine DLL eines Drittanbieters, die auf einer DataTable von Quellinformationen arbeiten und einige nützliche Werte generieren kann, und wir versuchen, es über SQLCLR, um als ein aufrufbar zu sein Tabellenwert UDF in SQL Server 2008.Pass-Tabelle als Parameter zu SQLCLR TV-UDF

Nimmt man das Konzept here einen Schritt weiter, würde ich gerne eine CLR Table-Valued Function programmieren, die auf einer Tabelle von Quelldaten aus der DB arbeitet.

Ich bin mir ziemlich sicher, dass ich verstehe, was auf der T-SQL-Seite der Dinge passieren muss; aber, Wie sollte die Methodensignatur im .NET (C#) Code aussehen? Was wäre der Parameterdatentyp für "Tabellendaten von SQL Server"?

z.B.

/* Setup */ 
CREATE TYPE InTableType 
AS TABLE (LocationName VARCHAR(50), Lat FLOAT, Lon FLOAT) 
GO 

CREATE TYPE OutTableType 
AS TABLE (LocationName VARCHAR(50), NeighborName VARCHAR(50), Distance FLOAT) 
GO 

CREATE ASSEMBLY myCLRAssembly 
FROM 'D:\assemblies\myCLR_UDFs.dll' 
WITH PERMISSION_SET = EXTERNAL_ACCESS 
GO 
CREATE FUNCTION GetDistances(@locations InTableType) 
RETURNS OutTableType 
AS 
EXTERNAL NAME myCLRAssembly.GeoDistance.SQLCLRInitMethod 
GO 

/* Execution */ 

DECLARE @myTable InTableType 
INSERT INTO @myTable(LocationName, Lat, Lon) VALUES('aaa', -50.0, -20.0) 
INSERT INTO @myTable(LocationName, Lat, Lon) VALUES('bbb', -20.0, -50.0) 
SELECT * FROM @myTable 

DECLARE @myResult OutTableType 
INSERT INTO @myResult 
GetDistances @myTable /* SQLCLR Call: GeoDistance.SQLCLRInitMethod(@myTable) */ 

Die lat/lon -> Entfernung Sache ist ein dummes Beispiel, das natürlich besser vollständig in SQL behandelt werden sollte; aber ich hoffe, dass es die allgemeine Absicht von Table-in -> Table-out durch eine Tabellenwert-UDF zeigt, die an eine SQLCLR-Assembly gebunden ist.

Ich bin nicht sicher, dass das möglich ist; Wie sieht die SQLCLRInitMethod-Methodensignatur in C# aus?

public class GeoDistance 
{ 
    [SqlFunction(FillRowMethodName = "FillRow")] 
    public static IEnumerable SQLCLRInitMethod(<appropriateType> myInputData) 
    { 
     //... 
    } 

    public static void FillRow(...) 
    { 
     //... 
    } 
} 

Wenn es nicht möglich ist, weiß ich, ich verwenden kann „Kontextverbindung = true“ SQL-Verbindung innerhalb des C# -Code have the CLR component query for the necessary data den entsprechenden Schlüssel gegeben; aber das ist empfindlich gegenüber Änderungen im DB-Schema. Also hoffe ich, dass SQL einfach alle Quelldaten bündelt und an die Funktion weitergibt.

Bonus Frage - vorausgesetzt, das funktioniert überhaupt, würde es auch mit mehr als eine Eingabe Tabelle funktionieren?

+0

mögliche Duplikate von [Pass-Tabelle als Parameter in SQL-Server UDF] (http://StackOverflow.com/Questions/1609115/Pass-Table-as-Parameter-Into-SQL-Server-Uudf) - Lukasz Lysiks Antwort ist Die Lösung für Ihre Frage: Sie müssen benutzerdefinierte Tabellentypen verwenden. –

+0

Richtig, ich sollte die Frage ein wenig klären. Ich frage speziell nach der Umsetzung der CLR-Komponente. Mir ist bewusst, was auf der T-SQL-Seite der Dinge geschehen muss (oder denke, dass ich bin - der Beispiel-t-SQL-Code wird veröffentlicht, um zu zeigen, wie ich davon ausgehe, dass es auf dieser Seite funktionieren muss dabei irgendwelche Fehler machen); Wie aber sollte die Methodensignatur in C# aussehen? Was sind die Methodenparameter für "Tabellendaten von SQL Server?" – Skeolan

+1

um es zu testen, erlauben Sie ein Objekt und geben Sie den Typ Name zurück :) –

Antwort

7

Es stellt sich heraus, dass es eine feste Liste gültiger Eingaben auf einer SQLCLR Funktion, bestimmt durch die verfügbare mapping between .NET datatypes and SQL datatypes

SQL-Datentyp „Tabelle“ ist ausdrücklich als mit keine Zuordnung durch die CLR angezeigt wird.

Daher ist es nicht möglich, tabellenwertige Daten als Methodenparameter in eine Tabellenwert-CLR-Funktion zu übergeben.

Alternativen

Es scheint möglich in tabellarische Daten zu erhalten über select ... for xml Verrenkungen in einen SqlXml Parameter zu füttern.

Ich habe erfolgreich SqlConnection conn = new SqlConnection("context connection = true"); im .NET-Code verwendet, damit TVF die Datenbank nach den benötigten Tabellendaten abfragen kann.

2

Diese Frage scheint (meistens) zu sein ist ein Duplikat:

CLR Table-valued function with array argument

Als kurze Notiz, in dieser Frage, die ich empfohlen: getrennte Liste, XML oder CLR UDT.

Es besteht auch die Möglichkeit, in der Funktion eine Tabelle zu füllen und die DataTable daraus zu laden.Die Verwendung einer realen Tabelle wird wahrscheinlich nicht empfohlen, da dies zusätzlichen Aufwand erfordern würde, um es "threadsicher" zu machen (Daten nicht mit anderen SPIDs zu kreuzen) und einen zusätzlichen Bereinigungsprozess erfordern würde, da die Funktion keine DML ausführen kann Anweisung, es zu bereinigen, sobald es mit den Daten fertig war. In bestimmten Situationen ist dies vielleicht bevorzugt, aber wahrscheinlich nicht für diesen speziellen Fall. Glücklicherweise sind die temporären Tabellen innerhalb von SQLCLR-Funktionen (schreibgeschützt, aber in T-SQL-Funktionen überhaupt nicht verfügbar) zugänglich. Die Verwendung von temporären Tabellen hätte die gleichen Vorteile wie die Verwendung von permanenten Tabellen, aber nicht die Nachteile von Kollisionen mit anderen SPIDs oder die Notwendigkeit einer separaten Bereinigung. Die einzige Anforderung besteht darin, dass Sie die Kontextverbindung verwenden, da dies die einzige Möglichkeit ist, auf sitzungsbasierte Objekte (d. H. Temporäre Tabellen) zuzugreifen.

Also für diesen speziellen Fall würde ich empfehlen, entweder die Temp-Tabelle oder XML-Optionen zu versuchen.