In Oracle it works well ......
Query for oracle is As Follows
Select distinct channel_id, position_id,datamonth,
percentile_cont(.9) within group (order by TRIM_PRE_ELIG_PAY)
over (partition by channel_id, position_id, datamonth) as TRIM_PRE_ELIG_PAY_90th_PERC
from Tablename
But for SQL Server, I'm getting an error. Here's the query for SQL Server 2008:
Select
distinct channel_id,
position_id, datamonth,
percentile_cont(.9) within group (order by TRIM_PRE_ELIG_PAY)
over (partition by channel_id) as TRIM_PRE_ELIG_PAY_90th_PERC
from table
ERROR: Select could not be parsed correctly. Output could not be
generated.
I got to know that it can work properly in SQL Server 2012 but need an alternative way in SQL Server 2008
Can anybody help...........
There is a workaround on the SQL Server Engine blog that applies to SQL Server 2005+
Unfortunately, it's quite long and convoluted: I'll leave you with the link rather than attempt to adapt it for your query...
You can create a CLR Aggregate function to implement the same. The only downfall is that you will have to re-arrange your query a bit. I implemented the percentile_cont using the CLR. Read here on how to create the CLR . Then you can use this code to get the same O/P as percentile_cont. Its a lot more easier than writing multiple statements.
You can definitely refine/tweak it a bit depending on your usage.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
Format.UserDefined,
IsInvariantToDuplicates = false,
IsInvariantToNulls = false,
IsInvariantToOrder = false,
MaxByteSize = 8000)]
public struct Percentile_Cont : IBinarySerialize
{
//Variables to hold the values;
private List<decimal> _list;
private decimal _percentile;
public void Init()
{
_list = new List<decimal>();
_percentile = new decimal();
}
public void Accumulate(SqlDecimal value,SqlDecimal percentile)
{
if (!value.IsNull)
{
_list.Add(value.Value);
_percentile = (decimal)percentile;
}
}
///
/// Merge the partially computed aggregate with this aggregate.
///
/// The other partial results to be merged
public void Merge(Percentile_Cont group)
{
this._list.AddRange(group._list.ToArray());
}
///
/// Called at the end of aggregation, to return the results.
///
/// The percentile of all inputted values
public SqlDecimal Terminate()
{
if (_list.Count == 0)
return SqlDecimal.Null;
_list.Sort();
if (_percentile < 0 || _percentile >= 1)
return SqlDecimal.Null;
var index =
(int) Math.Ceiling
(_percentile * _list.Count + 0.5m);
if(index > _list.Count)
{
index = index - 1;
}
return _list[index-1];
}
#region IBinarySerialize Members
public void Read(System.IO.BinaryReader binaryReader)
{
int cnt = binaryReader.ReadInt32();
this._list = new List<decimal>(cnt);
this._percentile = new decimal();
for (int i = 0; i < cnt; i++)
{
this._list.Add(binaryReader.ReadDecimal());
}
this._percentile = binaryReader.ReadDecimal();
}
public void Write(System.IO.BinaryWriter binaryWriter)
{
binaryWriter.Write(this._list.Count);
foreach (decimal d in this._list)
{
binaryWriter.Write(d);
}
binaryWriter.Write(_percentile);
}
#endregion
}
Related
I'm having a problem of defining a data type for a list of grouped rows in LINQ to SQL.
I have a model MyDBModel with 2 properties
public class MyDBModel
{
public List<a_Cases_tbl> a_Cases { get; set; }
public List<b_Cases_tbl> b_Cases { get; set; }
}
In a controller I try to get data into this properties
MyDBDataContext myDb = new MyDBDataContext();
var listModel = new MyDBModel();
listModel.a_Cases=
(from t in myDb.a_cases_table
group t by new { t.Date, t.Name, t.Category, t.Code }
into myGroup
select new { myGroup.Key.Date, myGroup.Key.Name, myGroup.Key.Category, myGroup.Key.Code });
listModel.b_Cases =
(from t in myDb.B_cases_table
group t by new { t.Date, t.Name, t.Category, t.Code }
into myGroup
select new { myGroup.Key.Date, myGroup.Key.Name, myGroup.Key.Category, myGroup.Key.Code });
I get error:
Cannot implicitly convert type 'System.Collections.Generic.List < AnonymousType#1 > ' to 'System.Collections.Generic.List < MVC4.a_Cases_tbl > '
What will Data type for a_Cases should be if the result is going to be a List of Grouped by Multiple columns? Or how to define List < IGrouping < Tkey, Telement > > if the result is grouped by multiple fields of different types?
In your code you have created the list of anonymous type. You must tell compiler that you create the objects of appropriate type.
select new a_Cases_tbl{ myGroup.Key.Date, myGroup.Key.Name, myGroup.Key.Category, myGroup.Key.Code });
....
select new b_Cases_tbl{ myGroup.Key.Date, myGroup.Key.Name, myGroup.Key.Category, myGroup.Key.Code });
I got two tables with data as listed below:
Table1: Student
Table2: Subject
I need the output as:
I got this acheived with below query using for XML PATH
Code:
WITH cte
AS ( SELECT Stu.Student_Id ,
Stu.Student_Name ,
( SELECT Sub.[Subject] + ','
FROM [Subject] AS Sub
WHERE Sub.Student_Id = Stu.Student_Id
ORDER BY Sub.[Subject]
FOR
XML PATH('')
) AS [Subjects]
FROM dbo.Student AS Stu
)
SELECT Student_id [Student Id] ,
student_name [Student Name] ,
SUBSTRING(Subjects, 1, ( LEN(Subjects) - 1 )) AS [Student Subjects]
FROM cte
My question is there a better way to do this without using XML Path?
This is a very good approach and has become pretty well accepted. There are several approaches and this blog post describes a lot of them.
One interesting approach that exists is using the CLR to do the work for you which will significantly reduce the complexity of the query with the trade-off of running external code. Here is a sample of what the class might look like in the assembly.
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;
[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize=8000)]
public struct strconcat : IBinarySerialize{
private List values;
public void Init() {
this.values = new List();
}
public void Accumulate(SqlString value) {
this.values.Add(value.Value);
}
public void Merge(strconcat value) {
this.values.AddRange(value.values.ToArray());
}
public SqlString Terminate() {
return new SqlString(string.Join(", ", this.values.ToArray()));
}
public void Read(BinaryReader r) {
int itemCount = r.ReadInt32();
this.values = new List(itemCount);
for (int i = 0; i <= itemCount - 1; i++) {
this.values.Add(r.ReadString());
}
}
public void Write(BinaryWriter w) {
w.Write(this.values.Count);
foreach (string s in this.values) {
w.Write(s);
}
}
}
And that would net a query a bit more like this.
SELECT CategoryId,
dbo.strconcat(ProductName)
FROM Products
GROUP BY CategoryId ;
Which is quite a bit simpler obviously. Take it for what it's worth :)
Good day!
I have multiple queries that I'd like to union together, then compile the entire thing. The uncompiled query runs fine, but an "InvalidOperationException: Member access 'Int32 Id' of 'UserQuery+Foo' not legal on type 'System.Linq.IQueryable`1[UserQuery+Foo]." exception is thrown when the same query is compiled and run.
How do I fix this?
void Main()
{
var db = new MyDataContext( "..." );
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from ab in GetA(dc).Union( GetB(dc) )
group ab by new { ab.Id, ab.Name } into grp
select new Foo
{
Id = grp.Key.Id,
Name = grp.Key.Name,
Total = grp.Count()
};
var final = CompiledQuery.Compile ( queryExpression );
var result1 = queryExpression.Compile () (db, 0); // calling the original query works fine
var result2 = final (db, 0); // calling the compiled query throws an exception
}
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public int Total { get; set; }
}
IQueryable<Foo> GetA( DataContext db )
{
return from b in db.GetTable<Bar>()
where b.IsActive
select new Foo { Id = b.Id, Name = b.Name };
}
IQueryable<Foo> GetB( DataContext db )
{
return from b in db.GetTable<Bar>()
where !b.IsActive
select new Foo { Id = b.Id, Name = b.Name };
}
EDIT
It looks like the union and grouping are irrelevant. Removing those elements from the query still causes an exception when compiled:
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from a in GetA(dc)
select new Foo
{
Id = a.Id,
Name = a.Name,
Total = 42
};
Replacing the call to GetA(dc) with dc.GetTable<Bar>() and adding the where clause fixes the issue.
So, is connecting separate queries together like this simply not possible for compiled queries?
EDIT #2
James' answer hit the nail on the head. Simplifying the query even further reveals the root problem:
Expression < Func < DataContext, int, IQueryable < Foo > > > queryExpression = (DataContext dc, int unused) =>
from a in GetA(dc)
select a;
This query throws NotSupportedException: Method 'System.Linq.IQueryable``1[UserQuery+Foo] GetA(System.Data.Linq.DataContext)' has no supported translation to SQL.
Pulling the call to GetA out into a separate variable assignment, then using that variable in the query throws a InvalidOperationException: Sequence contains more than one element exception.
I had the same issue and what seemed to do the trick for me was separating out an inline static method call that returned IQueryable<> so that I stored this deferred query into a variable and referenced that.
I think this is a bug in Linq to SQL but at least there is a reasonable workaround.
My guess is that the linq compiler doesn't understand the methods returning IQueryable.
To compile it, those methods would probably have to return some form of Expression<>.
It's my first LINQ TO SQL Project , So definitely my question could be naive .
Till now I used to create new property in Business Object beside of every DateTime Property , That's because i need to do some processing in my DateTime property and show it in special string format for binding to UI Controls .Like :
private DateTime _insertDate;
///
/// I have "InertDate" field in my Table on Database
///
public DateTime InsertDate
{
get { return _insertDate; }
set { _insertDate = value; }
}
// Because i need to do some processing I create a readonly string property that pass InsertDate to Utility method and return special string Date
public string PInsertDate
{
get { return Utility.ToSpecialDate(_insertDate); }
}
My question is I don't know how to do it in LINQ . I did like follow but i get run time error. "Method 'System.String ToSpecialDate(System.Object)' has no supported translation to SQL"
ToosDataContext db = new ToosDataContext();
var newslist = from p in db.News
select new {p.NewsId,p.Title,tarikh =MD.Utility.ToSpecialDate( p.ReleaseDate)};
GridView1.DataSource = newslist;
GridView1.DataBind();
You need to separate out the query performed in the database from the processing to be done in process. Try this:
var newslist = db.News
// First do a select in SQL
.Select(p => new {p.NewsId, p.Title, p.ReleaseDate})
.AsEnumerable() // Do the rest in process
.Select(p => new {p.NewsId, p.Title,
tarikh = MD.Utility.ToSpecialDate(p.ReleaseDate) });
so, i have a method: I'm counting a number in a sequence with holes, this number should be the first hole or max()
public static int GetRegisterNumber<T>(this IQueryable<T> enumerable, Func<T, bool> whereFunc, Func<T, int?> selectFunc)
{
var regNums = enumerable.OrderBy(selectFunc).Where(whereFunc).ToArray();
if (regNums.Count() == 0)
{
return 1;
}
for (int i = 0; i < regNums.Count(); i++)
{
if (i + 1 != regNums[i])
{
return regNums[i].Value + 1;
}
}
return regNums.Last().Value + 1;
}
i use it like:
var db = new SomeDataContext();
db.Goals.GetRegisterNumber(g => g.idBudget == 123, g => g.RegisterNumber);
So, i expect from linq some query like:
SELECT [t0].[id], [t0].[tstamp], [t0].[idBudget], [t0].[RegisterNumber], FROM [ref].[GoalHierarchy] AS [t0] WHERE [t0].[idBudget] = 123 ORDER BY [t0].[RegisterNumber]
instead i'm getting:
SELECT [t0].[id], [t0].[tstamp], [t0].[idBudget], [t0].[RegisterNumber], FROM [ref].[GoalHierarchy] AS [t0]
So linq gets ALL the table data and then filters it, but that behavior is not acceptable, because the table contains much data. Is there any solution?
Change your method signature to look like this:
public static int GetRegisterNumber<T>(this IQueryable<T> enumerable, Expression<Func<T, bool>> whereFunc, Expression<Func<T, int?>> selectFunc)
This way it will call the appropriate extension methods for IQueryable<T>. If you only have a Func<TSource, bool>, it will call the extension method for IEnumerable<T>.