Domanda

Sto ruotando i dati nella procedura memorizzata MS SQL. Le colonne pivotate vengono create dinamicamente utilizzando il parametro della procedura memorizzata (per esempio: "posizione1, posizione2, posizione3,"), quindi il numero di colonne che verranno generate non è noto. L'output dovrebbe apparire come (dove le posizioni sono prese dal parametro della procedura memorizzata):

  

OrderTime | Posizione1 | Posizione2 |   Location3

Qualche possibilità che questo possa essere usato in LINQ to SQL? Quando ho trascinato questa procedura nel file dbml, mostra che questa procedura restituisce int type.

Le colonne che utilizzo dalla tabella log_sales sono:

  • Posizione (varie posizioni su cui sto ruotando),
  • Addebito (importo del denaro)
  • OrderTime

Procedura memorizzata:

CREATE PROCEDURE [dbo].[proc_StatsDay] @columns NVARCHAR(64) AS

DECLARE @SQL_PVT1 NVARCHAR(512), @SQL_PVT2 NVARCHAR(512), @SQL_FULL NVARCHAR(4000);

SET @SQL_PVT1 =  'SELECT OrderTime, ' + LEFT(@columns,LEN(@columns)-1) +'
FROM (SELECT ES.Location, CONVERT(varchar(10), ES.OrderTime, 120),ES.Charge
        FROM dbo.log_sales ES
        ) AS D (Location,OrderTime,Charge)
        PIVOT (SUM (D.Charge) FOR D.Location IN
            (';
SET @SQL_PVT2 = ') )AS PVT
ORDER BY OrderTime DESC';

SET @SQL_FULL = @SQL_PVT1 + LEFT(@columns,LEN(@columns)-1) + 
@SQL_PVT2;       

EXEC sp_executesql @SQL_FULL, N'@columns NVARCHAR(64)',@columns = @columns

Nel file dbml designer.cs la mia parte di codice della procedura memorizzata:

[Function(Name="dbo.proc_StatsDay")]
public int proc_EasyDay([Parameter(DbType="NVarChar(64)")] string columns)
{
    IExecuteResult result = this.ExecuteMethodCall(this,((MethodInfo)MethodInfo.GetCurrentMethod())), columns);
    return ((int)(result.ReturnValue));
}
È stato utile?

Soluzione

Supponendo un'esigenza dinamica davvero terribile, è possibile utilizzare DataContext.ExecuteQuery

Basta montare un tipo che coprirà lo spazio dei risultati (i nomi delle proprietà devono corrispondere ai nomi delle colonne nella query):

public class DynamicResult
{
  public DateTime OrderDate {get;set;}
  public decimal? Location1 {get;set;}
  public decimal? Location2 {get;set;}
//..
  public decimal? Location100 {get;set;}
}

Quindi chiama

IEnumerable<DynamicResult> result =
  myDataContext.ExecuteQuery<DynamicResult>(commandString, param1);

Altri suggerimenti

È possibile creare l'oggetto linq per l'accesso dopo il set di dati restituito.

Ma sarebbe davvero utile. Linq sono utili per le chiamate typesafe e non per i risultati dinamici. Non sapresti cosa cercare in fase di compilazione.

Avresti eseguito la tua dichiarazione select

SELECT ES.Location, DateAdd(dd, DateDiff(dd, 0, ES.OrderTime), 0),ES.Charge
FROM dbo.log_sales ES

e acquisisci il risultato in un tipo come questo

public class LogSale
{
  public string Location {get;set;}
  public DateTime OrderDate {get;set;}
  public decimal Charge {get;set;}
}

E poi " pivot " / organizza quello in memoria

List<LogSale> source = LoadData();
var pivot = source
  .GroupBy(ls => ls.OrderDate)
  .OrderBy(g => g.Key)
  .Select(g => new {
     Date = g.Key,
     Details = g
       .GroupBy(ls => ls.Location)
       .Select(loc => new {
          Location = loc.Key,
          Amount = loc.Sum(ls => ls.Charge)
       })
     });

Ecco un secondo Linq pivoty che inserisce i dati in XML anziché in tipi anonimi.

var pivot = source
  .GroupBy(ls => ls.OrderDate)
  .OrderBy(g => g.Key)
  .Select(g => new XElement("Date",
    new XAttribute("Value", g.key),
    g.GroupBy(ls => ls.Location)
     .Select(loc => new XElement("Detail",
       new XAttribute("Location", loc.Key),
       new XAttribute("Amount", loc.Sum(ls => ls.Charge))
     ))
  ));
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top