select, зависящий от параметров
От: abb269  
Дата: 16.06.16 19:31
Оценка:
Здравствуйте,
Имеется несколько таблиц одинаковой структуры (столбцы k0, k1, day и res).
Нужно объединить значения 2..N таблиц со одинаковыми значениями k0 и k1, т.е. получить таблицу вида:
  • k0_табл1
  • k1_табл1
  • day_табл1
  • res_табл1
  • day_табл2
  • res_табл2
  • ...
  • day_таблN
  • res_таблN
    Очень не хочется писать метод для каждого N. Понимаю, что можно сделать в цикле, рекурентно. Тем более, что запрос join будет не самым трудным, но вот как написать к нему select с переменным числом параметров мне совсем не ясно.
    Иными словами:
    начало запроса
    var q = 
       from dr1 in dt1.AsEnumerable() // к чему присоединяем
       join dr2 in dt2.AsEnumerable() // что присоединяем
       on new {
          k0 = dr1["k0"],
          k1 = dr1["k1"]}
       equals new {
          k0 = dr2["k0"],
          k1 = dr2["k1"]}

    А дальше селект с переменным числом полей типа
    select new {
       k0 = dr1["k0"],
       k1 = dr1["k1"],
       day_1 = dr1["day"], // типа первый день, который уже в dt1
       res_1 = dr1["res"],
       ...
       day_n = dr1["day_n"], // типа последний день, который уже в dt1
       res_n = dr1["res_n"],
       day_n+1 = dr2["day"], // из dt2
       res_n+1 = dr2["res"],
    }

    Заранее благодарю за оперативный ответ
  • Re: select, зависящий от параметров
    От: Lexey Россия  
    Дата: 17.06.16 14:22
    Оценка:
    Здравствуйте, abb269, Вы писали:

    A>Имеется несколько таблиц одинаковой структуры (столбцы k0, k1, day и res).

    A>Нужно объединить значения 2..N таблиц со одинаковыми значениями k0 и k1, т.е. получить таблицу вида:
    A>
  • k0_табл1
  • k1_табл1
  • day_табл1
  • res_табл1
  • day_табл2
  • res_табл2
  • ...
  • day_таблN
  • res_таблN

    A>Очень не хочется писать метод для каждого N. Понимаю, что можно сделать в цикле, рекурентно. Тем более, что запрос join будет не самым трудным, но вот как написать к нему select с переменным числом параметров мне совсем не ясно.


    Не совсем ясно, что потом с результатом делать. Допустим, получишь ты анонимный класс с переменным числом полей (через рефлекшен или экспрешены такое можно сотворить), а как его использовать потом?
  • "Будь достоин победы" (c) 8th Wizard's rule.
    Отредактировано 17.06.2016 14:23 Lexey . Предыдущая версия .
    Re: select, зависящий от параметров
    От: bnk СССР http://unmanagedvisio.com/
    Дата: 17.06.16 16:36
    Оценка:
    Здравствуйте, abb269, Вы писали:

    A>Здравствуйте,

    A>Имеется несколько таблиц одинаковой структуры (столбцы k0, k1, day и res).
    A>Нужно объединить значения 2..N таблиц со одинаковыми значениями k0 и k1, т.е. получить таблицу вида:
    A>
  • k0_табл1
  • k1_табл1
  • day_табл1
  • res_табл1
  • day_табл2
  • res_табл2
  • ...
  • day_таблN
  • res_таблN
    A>Очень не хочется писать метод для каждого N. Понимаю, что можно сделать в цикле, рекурентно. Тем более, что запрос join будет не самым трудным, но вот как написать к нему select с переменным числом параметров мне совсем не ясно.

    A>Заранее благодарю за оперативный ответ


    IMHO сложно будет. Кода будет больше, че м если тупо функции наделать для каждого N.

    Я имею в виду если делать через Expression.

    Например есть dynamiclinq, но оно джойны не умеет.
  • Re[2]: select, зависящий от параметров
    От: bnk СССР http://unmanagedvisio.com/
    Дата: 17.06.16 19:53
    Оценка:
    Здравствуйте, bnk, Вы писали:

    bnk>Например есть dynamiclinq, но оно джойны не умеет.


    dynamic linq

    Оказывается на самом деле уже дописали метод для JOIN.
    С ним все вроде получается не так уж и сложно

            // для теста
            class Row
            {
                public string k0 { get; set; }
                public string k1 { get; set; }
                public int day { get; set; }
                public int res { get; set; }
            }
    
            const int N = 3;
            static Row[][] tables = 
            {
                new []
                {
                    new Row {k0 = "0", k1 = "42", day = 10, res = 100},
                    new Row {k0 = "1", k1 = "43", day = 10, res = 100},
                    new Row {k0 = "2", k1 = "44", day = 10, res = 100},
                },
                new []
                {
                    new Row {k0 = "0", k1 = "42", day = 20, res = 200},
                    new Row {k0 = "1", k1 = "43", day = 20, res = 200},
                    new Row {k0 = "3", k1 = "44", day = 20, res = 200},
                },
                new []
                {
                    new Row {k0 = "0", k1 = "42", day = 30, res = 300},
                    new Row {k0 = "1", k1 = "43", day = 30, res = 300},
                    new Row {k0 = "4", k1 = "44", day = 30, res = 300},
                }
            };
    
            static void Main(string[] args)
            {
                // собственно код
                IQueryable query = tables[0].AsQueryable().Select("new(k0, k1, day as day0, res as res0)");
    
                foreach (var i in Enumerable.Range(1, N - 1))
                {
                    var fields = string.Join("", Enumerable.Range(0, i).Select(n => $"inner.day{n}, inner.res{n}, "));
                    var result = $"new(inner.k0, inner.k1, {fields} outer.day as day{i}, outer.res as res{i})";
    
                    query = tables[i].AsQueryable().Join(query, "new(k0, k1)", "new(k0, k1)", result);
                }
                // вуаля :)
    
                foreach (var result in query)
                    Console.WriteLine(result);
    
                Console.ReadLine();
            }
    Re[3]: select, зависящий от параметров
    От: abb269  
    Дата: 18.06.16 10:03
    Оценка:
    bnk, это фантастика! большое Вам спасибо!

    Рано обрадовался. Моих знаний явно не хватает, чтобы переделать класс в роу.
                // fill dt1
                DataTable dt1 = new DataTable();
                dt1.Columns.Add("k0", typeof(int));
                dt1.Columns.Add("k1", typeof(string));
                dt1.Columns.Add("day", typeof(int));
                dt1.Columns.Add("res", typeof(int));
                for (int i = 0; i < 5; i++)
                {
                    int k0 = i;
                    string k1 = (i * 2).ToString();
                    int day = i * 10;
                    int res = i * 11;
                    dt1.Rows.Add(new object[] { k0, k1, day, res });
                }          
    
                // fill dt2
                DataTable dt2 = dt1.Clone();
                for (int i = 0; i < 5; i++)
                {
                    int k0 = i;
                    string k1 = (i * 2).ToString();
                    int day = i * 10 + 3;
                    int res = i * 11 + 3;
                    dt2.Rows.Add(new object[] { k0, k1, day, res });
                }
    
                List<DataTable> dtList = new List<DataTable>();
                dtList.Add(dt1);
                dtList.Add(dt2);
    
                query =
                    dtList[0].AsEnumerable().AsQueryable().
                    Select("new(k0, k1, day as day0, res as res0)");

    Вот этот вот фрагмент заканчивается исключением
    "System.Linq.Dynamic.ParseException" в DynamicJoin.exe

    Дополнительные сведения: No property or field 'k0' exists in type 'DataRow'


    Может в этом джойне и нельзя использовать роу и надо все решать через классы?
    Отредактировано 18.06.2016 19:04 abb269 . Предыдущая версия .
    Re[4]: select, зависящий от параметров
    От: abb269  
    Дата: 18.06.16 19:06
    Оценка:
    A>bnk, это фантастика! большое Вам спасибо!

    Рано обрадовался. Моих знаний явно не хватает, чтобы переделать класс в роу.
                // fill dt1
                DataTable dt1 = new DataTable();
                dt1.Columns.Add("k0", typeof(int));
                dt1.Columns.Add("k1", typeof(string));
                dt1.Columns.Add("day", typeof(int));
                dt1.Columns.Add("res", typeof(int));
                for (int i = 0; i < 5; i++)
                {
                    int k0 = i;
                    string k1 = (i * 2).ToString();
                    int day = i * 10;
                    int res = i * 11;
                    dt1.Rows.Add(new object[] { k0, k1, day, res });
                }          
    
                // fill dt2
                DataTable dt2 = dt1.Clone();
                for (int i = 0; i < 5; i++)
                {
                    int k0 = i;
                    string k1 = (i * 2).ToString();
                    int day = i * 10 + 3;
                    int res = i * 11 + 3;
                    dt2.Rows.Add(new object[] { k0, k1, day, res });
                }
    
                List<DataTable> dtList = new List<DataTable>();
                dtList.Add(dt1);
                dtList.Add(dt2);
    
                query =
                    dtList[0].AsEnumerable().AsQueryable().
                    Select("new(k0, k1, day as day0, res as res0)");

    Вот этот вот фрагмент заканчивается исключением
    "System.Linq.Dynamic.ParseException" в DynamicJoin.exe

    Дополнительные сведения: No property or field 'k0' exists in type 'DataRow'


    Может в этом джойне и нельзя использовать роу и надо все решать через классы?
    Re[5]: select, зависящий от параметров
    От: _Raz_  
    Дата: 18.06.16 20:10
    Оценка:
    Здравствуйте, abb269, Вы писали:

    A> Select("new(k0, k1, day as day0, res as res0)");


    Select("new(ItemArray[0] as k0, ItemArray[1] as k1, ItemArray[2] as day0, ItemArray[3] as res0)")
    или
    Select("new(it[\"k0\"] as k0, it[\"k1\"] as k1, it[\"day\"] as day0, it[\"res\"] as res0)")
    ... << RSDN@Home (RF) 1.2.0 alpha 5 rev. 78>>
    Re[6]: select, зависящий от параметров
    От: abb269  
    Дата: 18.06.16 21:30
    Оценка:
    Здравствуйте, _Raz_, Вы писали:

    _R_>Здравствуйте, abb269, Вы писали:


    A>> Select("new(k0, k1, day as day0, res as res0)");


    _R_>Select("new(ItemArray[0] as k0, ItemArray[1] as k1, ItemArray[2] as day0, ItemArray[3] as res0)")

    _R_>или
    _R_>Select("new(it[\"k0\"] as k0, it[\"k1\"] as k1, it[\"day\"] as day0, it[\"res\"] as res0)")

    _Raz_, большое спасибо!
    Но теперь все равно исключение дальше, которое сильнее меня:
                // fill dt1
                DataTable dt1 = new DataTable();
                dt1.Columns.Add("k0", typeof(int));
                dt1.Columns.Add("k1", typeof(string));
                dt1.Columns.Add("day", typeof(int));
                dt1.Columns.Add("res", typeof(int));
                for (int i = 0; i < 5; i++)
                {
                    int k0 = i;
                    string k1 = (i * 2).ToString();
                    int day = i * 10;
                    int res = i * 11;
                    dt1.Rows.Add(new object[] { k0, k1, day, res });
                }          
    
                // fill dt2
                DataTable dt2 = dt1.Clone();
                for (int i = 0; i < 5; i++)
                {
                    int k0 = i;
                    string k1 = (i * 2).ToString();
                    int day = i * 10 + 3;
                    int res = i * 11 + 3;
                    dt2.Rows.Add(new object[] { k0, k1, day, res });
                }
    
                List<DataTable> dtList = new List<DataTable>();
                dtList.Add(dt1);
                dtList.Add(dt2);
    
                query =
                    dtList[0].AsEnumerable().AsQueryable().
                    Select("new(it[\"k0\"] as k0, it[\"k1\"] as k1, it[\"day\"] as day0, it[\"res\"] as res0)");
    
                foreach (var i in Enumerable.Range(1, 3 - 1))
                {
                    var fields = string.Join(
                        "",
                        Enumerable.Range(0, i).Select(n => $"inner.day{n}, inner.res{n}, ")
                        );
                    var result = $"new(inner.k0, inner.k1, {fields} outer.day as day{i}, outer.res as res{i})";
    
                    // тут в query вот так
                    // "System.Linq.Dynamic.ParseException" в DynamicJoin.exe
                    // Дополнительные сведения: Expression is missing an 'as' clause
                    query = dtList[i].AsEnumerable().AsQueryable().
                        Join(query,
                        "new(new(it[\"k0\"] as k0, it[\"k1\"] as k1)",
                        "new(new(it[\"k0\"] as k0, it[\"k1\"] as k1)", 
                        result);
                }
    
                string sr = "";
                foreach (var result in query)
                    sr += result + "\n";


    Если Join(query, "new(k0, k1)", "new(k0, k1)", result), то ожидаемо получаю:
    No property or field 'k0' exists in type 'DataRow'
    Re[7]: select, зависящий от параметров
    От: bnk СССР http://unmanagedvisio.com/
    Дата: 18.06.16 23:30
    Оценка:
    Здравствуйте, abb269, Вы писали:

    A>Если Join(query, "new(k0, k1)", "new(k0, k1)", result), то ожидаемо получаю:

    A> No property or field 'k0' exists in type 'DataRow'

    Для DataRow можно переименовать колонки:

            static DataTable BuildTable(int n)
            {
                var dt = new DataTable();
    
                dt.Columns.Add("k0", typeof(string));
                dt.Columns.Add("k1", typeof(string));
                dt.Columns.Add("day", typeof(int));
                dt.Columns.Add("res", typeof(int));
    
                dt.Rows.Add("0", "42", n * 10, n * 100);
                dt.Rows.Add("1", "43", n * 20, n * 200);
                dt.Rows.Add("2", "44", n * 30, n * 300);
    
                return dt;
            }
            
            const int N = 3;
    
            static void Main(string[] args)
            {
                var tables = Enumerable.Range(0, N).Select(n => BuildTable(n).AsEnumerable()).ToList();
                
                IQueryable query = tables[0].AsQueryable().Select("new(get_Item(0) as k0, get_Item(1) as k1, get_Item(2) as day0, get_Item(3) as res0)");
    
                foreach (var i in Enumerable.Range(1, N - 1))
                {
                    var fields = string.Join("", Enumerable.Range(0, i).Select(n => $"inner.day{n}, inner.res{n}, "));
                    var select = $"new(inner.k0, inner.k1, {fields} outer.day as day{i}, outer.res as res{i})";
    
                    query =
                        tables[i].AsQueryable()
                        .Select("new(get_Item(0) as k0, get_Item(1) as k1, get_Item(2) as day, get_Item(3) as res)")
                        .Join(query, "new(k0, k1)", "new(k0, k1)", select);
                }
    
                foreach (var result in query)
                    Console.WriteLine(result);
    
                Console.ReadLine();
            }
    Re[8]: select, зависящий от параметров
    От: abb269  
    Дата: 19.06.16 03:09
    Оценка:
    bnk, еще раз спасибо Вам!

    Однако, в Вашем фрагменте объявление
    IQueryable query = tables[0].AsQueryable().Select("new(get_Item(0) as k0, get_Item(1) as k1, get_Item(2) as day0, get_Item(3) as res0)");

    генерит исключение
    Methods on type 'DataRow' are not accessible
    Re[9]: select, зависящий от параметров
    От: bnk СССР http://unmanagedvisio.com/
    Дата: 19.06.16 10:04
    Оценка:
    Здравствуйте, abb269, Вы писали:

    A>генерит исключение

    A>Methods on type 'DataRow' are not accessible

    Можно добавить "typeof(Data.DataRow)" в список "predefinedTypes", или "get_Item(X)" заменить на "ItemArray[X]". Должно завестить!
    Re[10]: select, зависящий от параметров
    От: abb269  
    Дата: 19.06.16 17:24
    Оценка: 3 (1)
    Здравствуйте, bnk, Вы писали:

    bnk>Можно добавить "typeof(Data.DataRow)" в список "predefinedTypes", или "get_Item(X)" заменить на "ItemArray[X]". Должно завестить!


    Завелось, очень даже. Огромное спасибо Вам за помощь!
    На работе небольшой тотализатор, обещаю ставить только на Австрию
    Re: select, зависящий от параметров
    От: Sinclair Россия https://github.com/evilguest/
    Дата: 20.06.16 06:54
    Оценка:
    Здравствуйте, abb269, Вы писали:

    A>Здравствуйте,

    A>Имеется несколько таблиц одинаковой структуры (столбцы k0, k1, day и res).
    A>Нужно объединить значения 2..N таблиц со одинаковыми значениями k0 и k1, т.е. получить таблицу вида:
    A>
  • k0_табл1
  • k1_табл1
  • day_табл1
  • res_табл1
  • day_табл2
  • res_табл2
  • ...
  • day_таблN
  • res_таблN
    1. Является ли (k0, k1) первичным ключом в каждой таблице?
    2. Бывает ли так, что в какой-то из таблиц нету какого-то из значений (k0, k1)?
    3. Зачем вам именно такая структура? Почему бы не разворачивать на клиенте, построив запрос через union all?
    4. Откуда взялось переменное число параметров? В вашем запросе параметров вовсе нет.
  • Уйдемте отсюда, Румата! У вас слишком богатые погреба.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.