Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.

January 27, 2010 / by Zsolt Soczó

SQLCLR deplyment hiba

Error: Incorrect syntax near valami.
Akkor jön elő, ha az SQLCLR assemblyt és benne a függvényeket akarja az VS deployolni. Több oka lehet, most az volt, hogy egy .NET oldalon double-t visszaadó függvény véletlenül így lett deklarálva:

[SqlFunction(…, TableDefinition = “Datum datetime, Szazalek double”)]

Mi a hiba benne? SQL Serverben nincs double, csak real és float. Ráadásul a C# float az az SQL real és a C# double az SQL Server float (kb.). :)

Az előbbi helyesen:

[SqlFunction(…, TableDefinition = “Datum datetime, Szazalek float”)]

Miért kellett SQLCLR függvényt írni? A futó aggregálások (én legalábbis nem tudok jobbat kurzor nélkül) o(n2)-es algoritmusok, ezt CLR-ben könnyen meg lehet írni o(n)-re. Pl:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

public class UserDefinedFunctions
{
internal class Result
{
public long RowId;
public double CumDollarGain;
public double TopDollarGain;
public double DollarDrawDown;
}

//Input table: create table #trades(RowId long, DollarGain money, other columns possible)
[SqlFunction(FillRowMethodName = “FillRow”, DataAccess = DataAccessKind.Read,
TableDefinition = “RowId bigint, CumDollarGain float, TopDollarGain float, DollarDrawDown float”)]
public static IEnumerable Cumul()
{
using (var conn = new SqlConnection(“Context connection=true”))
{
using (var cmd = new SqlCommand(“select RowID, DollarGain from #trades”, conn))
{
var res = new List();
conn.Open();
double cumulPrice = 0, topPrice = 0, drawDawn = 0;

using (SqlDataReader r = cmd.ExecuteReader())
{
int idCol = r.GetOrdinal(“RowID”);
int gainCol = r.GetOrdinal(“DollarGain”);

while (r.Read())
{
var price = r.GetDouble(gainCol);

cumulPrice += price;
topPrice = Math.Max(price, topPrice);

drawDawn += price;
drawDawn = Math.Min(drawDawn, 0);

res.Add(new Result
{
RowId = r.GetInt64(idCol),
CumDollarGain = cumulPrice,
TopDollarGain = topPrice,
DollarDrawDown = drawDawn
});
}
return res;
}
}
}
}
public static void FillRow(object obj,
out long id,
out double cumDollarGain,
out double topDollarGain,
out double dollarDrawDown)
{
var r = (Result)obj;
id = r.RowId;
cumDollarGain = r.CumDollarGain;
topDollarGain = r.TopDollarGain;
dollarDrawDown = r.DollarDrawDown;
}
};

Sajnos nem lehet átpasszolni a megnyitott SqlDataReadert a két metódus között, ezért kénytelen az ember letárolni az eredményhalmazt. Persze pár ezer sornál ez nem gond.

Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.

LEAVE A COMMENT

3 COMMENTS

  • hrongyorgy January 27, 2010

    Ezt nem ertem. Elvben ugye a SQL2k8 majdnem teljesen dotnetbe irodott. A SQLCLR mint olyan szinten dotnet. Ket dotnet alkalmazas kozt miert nem lehet egyutasan deployolni a kulonbozo szamabrazolasi tipusokat? Biztos megint en nem ertek valamit.

  • Soczó Zsolt January 27, 2010

    Az attributumos leírásban sql típusokat kell használni. Attól, hogy .net integrált az sql server a belső típusaik, amiket táblákban használunk még nem változtak.
    Az SQL 2008 nem .netben íródott, csak a kliens eszközök. A szerve maga csuma natív, kivéve a .net illesztést.

  • Szindbad January 28, 2010

    Hat ja, attributumban stringkent meg azt a keves pszeudo-tipusossagot is elvesziti az ember, amit a stored procedure nyujt.