Firebird集团按期间划分

时间:2016-08-01 11:59:48

标签: c# linq 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执行此操作?

3 个答案:

答案 0 :(得分:0)

在MoreLinq中有一个Lag扩展方法,但只有Linq to Objects ...

支持它

如果您正在寻找C#linq答案,那么您可以做什么:

基本上以正确的方式对数据进行排序,然后添加行索引,而价格(和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的beta版本),那么:

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();

答案 1 :(得分: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;

答案 2 :(得分: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();

        }
    }
}