2016-08-01 4 views
1

で私は以下のようにFirebirdデータベースから、いくつかの過去のデータを引っ張っています:私が何をしようとしています何Firebirdのグループは、期間

Product_ID  Date  Price 
1   2001-01-01 10 
1   2001-02-01 10 
1   2001-03-01 15 
1   2001-04-01 10 
1   2001-05-01 20 
1   2001-06-01 20 

が発生すべての価格変更のための最初を抽出することです。期待されるデータ・セットの 例:

Product_ID  Date  Price 
1   2001-01-01 10 
1   2001-03-01 15 
1   2001-04-01 10 
1   2001-05-01 20 

私はMSSQLに私はそのためのLAGを活用できることを知っています。 Firebirdでそれを行うことは可能ですか?

MoreLinqで
+0

これでストアドプロシージャを簡単に使用できます。すべてのレコード( 'FOR SELECT ..... INTO ... ORDER BY .....')と価格変更によって 'SUSPEND'が呼び出されます。 –

+0

または、試してみてください(ここではFirebirdのインスタンスはありません): 'Product_ID、MIN(Date)、FROM xxx GROUP BY Product_ID、Date、Price' –

+0

これは同じ価格の最初のインスタンスだけを取得します。それは2番目の価格変更(04-01の10)を取得しません – Ninjago

答えて

0

...そこラグ拡張メソッドであるが、それはオブジェクトへのLINQでのみサポートされて

あなたは何ができるか、あなたはそのためのC#のLINQの答えを探している場合は次のことができます。

基本的にはデータを正しい方法で並べ替え、次に行インデックスを追加する間はprice(およびproduct_id)は同じです。グループ化して、minの日付を選択します。その後、

int groupingIndex = 0; 
int previousPrice = 0; 

var response = data 
    .OrderBy(item => item.Product_ID) 
    .ThenBy(item => item.Date) 
    .Select(item => 
    { 
     if (item.Price != previousPrice) 
     { 
      previousPrice = item.Price; 
      groupingIndex++; 
     } 

     return new { Index = groupingIndex, Item = item }; 
    }) 
    .GroupBy(item => new { item.Index, item.Item.Product_ID, item.Item.Price }) 
    .Select(group => new Record 
    { 
     Product_ID = group.Key.Product_ID, 
     Price = group.Key.Price, 
     Date = group.Min(item => item.Item.Date) 
    }).ToList(); 

そして、あなたは、C#での操作を行うことなくDB(およびMoreLinqのベータ版を使用して)気にしない場合:

int index = 0; 

var result2 = data 
    .OrderBy(item => item.Product_ID) 
    .ThenBy(item => item.Date) 
    .Lag(1, (current, previous) => new { Index = (current.Price == previous?.Price ? index : ++index), Item = current }) 
    .GroupBy(item => new { item.Index, item.Item.Product_ID, item.Item.Price }) 
    .Select(group => new Record { Product_ID = group.Key.Product_ID, Price = group.Key.Price, Date = group.Min(item => item.Item.Date) }) 
    .ToList(); 
0

あなたはこれを試すことができるが意識し、私はそれをテストしていませんでした:

CREATE PROCEDURE SP_Test 
RETURNS (
    Product_ID INTEGER, 
    Date DATE, 
    Price INTEGER 
) 
AS 
DECLARE VARIABLE Last_Product_ID INTEGER; 
DECLARE VARIABLE Last_Date DATE; 
DECLARE VARIABLE Last_Price INTEGER; 
BEGIN 
    FOR SELECT Product_ID, Date, Price 
     FROM xxxx 
     ORDER BY Product_ID, Date 
     INTO Product_ID, Date, Price 
    DO BEGIN 
    IF ((:Last_Product_ID IS NULL) OR 
     (:Last_Date IS NULL) OR 
     (:Last_Price IS NULL) OR 
     (:Product_ID <> :Last_Product_ID) OR 
     (:Price <> :Last_Price)) THEN 
     SUSPEND; 
    Last_Product_ID = :Product_ID; 
    Last_Date = :Date; 
    Last_Price = :Price; 
    END;  
END; 
+0

または永続的なSPを作成する代わりにEXECTE BLOCKを使用することができます –

0

これは少し複雑ですが、それは

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Data; 

namespace ConsoleApplication6 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      DataTable dt = new DataTable(); 
      dt.Columns.Add("Product_ID", typeof(int)); 
      dt.Columns.Add("Date", typeof(DateTime)); 
      dt.Columns.Add("Price", typeof(int)); 

      dt.Rows.Add(new object[] {1, DateTime.Parse("2001-01-01"), 10}); 
      dt.Rows.Add(new object[] {1, DateTime.Parse("2001-02-01"), 10}); 
      dt.Rows.Add(new object[] {1, DateTime.Parse("2001-03-01"), 15}); 
      dt.Rows.Add(new object[] {1, DateTime.Parse("2001-04-01"), 10}); 
      dt.Rows.Add(new object[] {1, DateTime.Parse("2001-05-01"), 20}); 
      dt.Rows.Add(new object[] {1, DateTime.Parse("2001-06-01"), 20}); 
      dt.Rows.Add(new object[] { 2, DateTime.Parse("2001-01-01"), 10 }); 
      dt.Rows.Add(new object[] { 2, DateTime.Parse("2001-02-01"), 10 }); 
      dt.Rows.Add(new object[] { 2, DateTime.Parse("2001-03-01"), 15 }); 
      dt.Rows.Add(new object[] { 2, DateTime.Parse("2001-04-01"), 10 }); 
      dt.Rows.Add(new object[] { 2, DateTime.Parse("2001-05-01"), 20 }); 
      dt.Rows.Add(new object[] { 2, DateTime.Parse("2001-06-01"), 20 }); 

      dt = dt.AsEnumerable().OrderBy(x => x.Field<DateTime>("Date")).CopyToDataTable(); 
      List<DataRow> results = dt.AsEnumerable() 
       .GroupBy(g => g.Field<int>("Product_ID")) 
       .Select(g1 => g1.Select((x, i) => new { row = x, dup = (i == 0) || ((i > 0) && (g1.Skip(i - 1).FirstOrDefault().Field<int>("Price") != g1.Skip(i).FirstOrDefault().Field<int>("Price"))) ? false : true }) 
       .Where(y => y.dup == false).Select(z => z.row)).SelectMany(m => m).ToList(); 

     } 
    } 
} 
の作品
+0

ありがとうございます。 Product_IDも考慮するにはどうすればよいですか? – Ninjago

+0

それはかなりではありませんが、私はコードを更新しました。 – jdweng