Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WinForms, .Net Framework Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 BulkCopy в N таблиц из 1 источника  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3410
Есть плоский файл, в каждой строке по ~300 полней.
Есть маппинг полей в файле к полям в таблицах.
смысл в том, чтоб за одну прочитанную строку Reader'ом, добавить в таблицы записи согласно маппингу.
Косяк в том, что BulkCopy принимает в качестве параметров только 1 таблицу и только 1 источник.
Следовательно, мне придется выполнять пакетную вставку для каждой таблички отдельно и каждый раз перечитывать файл источник
Сиквенс у меня сквозной и заранее известный для всех строк, вопрос только в том, как за 1 проход вставить во все таблички записи.
Или придется колхозить свой BulkCopy?
27 июн 18, 18:36    [21526136]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Roman Mejtes
Есть маппинг полей в файле к полям в таблицах.
как выглядит?
Или ручной формат?
27 июн 18, 19:06    [21526249]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Roman Mejtes
колхозить
разве конвертнуть файл данных или разбить на несколько по числу таблиц хуже чем колхозить?
Всегда лучше подогнать формат под сиквел чем чем сиквел под твой формат.
imho
27 июн 18, 19:51    [21526372]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2372
Roman Mejtes,

сделать несложно - вьха + INSTEAD OF Trigger
27 июн 18, 20:21    [21526488]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2372
LR
Roman Mejtes,

сделать несложно - вьха + INSTEAD OF Trigger

т.е., в эту вьюху и заливать BulkCopy, ну а в триггере уже распихивать по таблицам
create trigger TrInsVw on MyVw instead of insert
as
begin
	insert into tbl1 select c11, c12,... from inserted
	insert into tbl2 select c21, c22,... from inserted
        ...
end
27 июн 18, 20:27    [21526510]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
LR
вьха + INSTEAD OF Trigger
прикольно.
Но тогда можно и залить все в одну таблу и раскидать потом.
27 июн 18, 20:31    [21526525]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2372
Petro123
LR
вьха + INSTEAD OF Trigger
прикольно.
Но тогда можно и залить все в одну таблу и раскидать потом.

Так ведь "instead of", зачем еще в какую-то таблицу? (Во вьюху напрямую нельзя залить, если базовых таблиц несколько).
27 июн 18, 20:42    [21526550]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2372
LR
Так ведь "instead of", зачем еще в какую-то таблицу? (Во вьюху напрямую нельзя залить, если базовых таблиц несколько).
Вернее, вьюха - это лишь оболочка (над таблицей/ами) - заливать можно лишь в таблицы, но можно и _через_ вьюхи (если базовая таблица одна), в т.ч. можно и через такие вот триггеры - вьюха задает формат данных (перечень полей), а в триггере можно уже делать все что угодно, ссылаясь на заливаемые данные как на inserted.
27 июн 18, 20:51    [21526571]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
LR,
Да знаю я что такое триггер.
Просто это уже не совсем импорт.
По мне лучше
util.exe table1
util.exe table2
сделать.
Но выбирать автору.
Мне нравится разнообразие идей.
27 июн 18, 21:09    [21526600]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Изопропил
Member

Откуда:
Сообщений: 31186
Roman Mejtes
и каждый раз перечитывать файл источник

ничего страшного
27 июн 18, 21:20    [21526620]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5034
Roman Mejtes
Или придется колхозить свой BulkCopy?

Колхозить свой именно bulk (т.е. аналог BULK INSERT) - проще убиться. TDS-протокол - это то еще развлечение, я это проходил. Проще действительно view+триггер. Или залить во временную таблицу и раскидать обычным T-SQL батчем в одной транзакции.
28 июн 18, 06:47    [21526962]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
hVostt
Member

Откуда:
Сообщений: 15626
Roman Mejtes
...
Сиквенс у меня сквозной и заранее известный для всех строк, вопрос только в том, как за 1 проход вставить во все таблички записи.
Или придется колхозить свой BulkCopy?


Варианты: с триггерами, процедурами и вариациями -- сразу нет.

Правильно: Bulk в специальную таблицу импорта с полями 1 к 1, как в файле. Такую таблицу можно даже создавать на лету под каждый такой импорт. Потом, загруженные записи из таблицы перекладываешь как хочешь куда хочешь SQL-инструкциями.

Что это даёт: транзакционность, полный контроль, асинхронность с возможностью отслеживать процесс в любой момент, возможность постобработки, валидации и проверки со всякими джойнами и т.д.

Подходит для большинства задач интеграции больших и средних объёмов данных.

А триггеры, процедуры и прочая ересь, это однозначно бууэээ... Никогда так не делай. Никогда.
28 июн 18, 07:03    [21526983]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
hVostt
Member

Откуда:
Сообщений: 15626
Сон Веры Павловны
Или залить во временную таблицу и раскидать обычным T-SQL батчем в одной транзакции.


Только так
28 июн 18, 07:04    [21526984]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
hVostt
Правильно: Bulk в специальную таблицу импорта с полями 1 к 1, как в файле.

Если формат файла не печатала Маша на машинке.
Конвертация файла занимает секунды. Импорт по сети - минуты.
Ну и ещё бывают один ко многим данные. Опять же предварительный конверт файла входного.
28 июн 18, 07:19    [21526999]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
hVostt
Member

Откуда:
Сообщений: 15626
Petro123
hVostt
Правильно: Bulk в специальную таблицу импорта с полями 1 к 1, как в файле.

Если формат файла не печатала Маша на машинке.
Конвертация файла занимает секунды. Импорт по сети - минуты.
Ну и ещё бывают один ко многим данные. Опять же предварительный конверт файла входного.


Если нарушение типов это одно, тогда это не верный формат файла, забулкать в любом случае не получится, только порциями, дополнительно выделив корректные данные с точки зрения типов.

Остальное лучше делать, когда данные в БД.
28 июн 18, 07:24    [21527004]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Алексей К
Member

Откуда: Новосибирск
Сообщений: 13633
1. Написать хранимую процедуру добавления одной записи в N-таблиц.

2. Сгенерировать SQL-пакет, содержащий N вызовов этой хранимой процедуры.

3. Не забыть про set nocount on
28 июн 18, 07:25    [21527008]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
hVostt
Petro123
пропущено...

Если формат файла не печатала Маша на машинке.
Конвертация файла занимает секунды. Импорт по сети - минуты.
Ну и ещё бывают один ко многим данные. Опять же предварительный конверт файла входного.


Если нарушение типов это одно, тогда это не верный формат файла, забулкать в любом случае не получится, только порциями, дополнительно выделив корректные данные с точки зрения типов.

Остальное лучше делать, когда данные в БД.
да.
Плюс еще корпоративная политика.
Иногда БЛ бизнес логика не в базе.
База просто таблички, а вся логика в классах.
Тогда тоже я лучше разобью на 10 файлов одну простынь 300 полей и в потоках в фоне вставлю.
Автору там виднее. Решений миллион.
28 июн 18, 07:37    [21527015]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 5034
А еще, как вариант, сделать для загрузки SSIS-пакет, и запускать его программно. Внутри пакета раскладывать данные в отдельные таблицы. Тогда не нужно будет использовать T-SQL.
28 июн 18, 07:39    [21527019]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
Сон Веры Павловны
SSIS
действительно.
Про ETL забыли.
Это его основная задача как у сабжа.
28 июн 18, 07:46    [21527025]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
hVostt
Member

Откуда:
Сообщений: 15626
Petro123
да.
Плюс еще корпоративная политика.
Иногда БЛ бизнес логика не в базе.
База просто таблички, а вся логика в классах.
Тогда тоже я лучше разобью на 10 файлов одну простынь 300 полей и в потоках в фоне вставлю.
Автору там виднее. Решений миллион.


Тут речь не про логику. Логика, где бы она ни была, может работать не так быстро, как простая вставка. Например, банально, подсасывание справочников, проверка на дубли, валидация и т.д. Варианты на триггерах и процедурах ущербны чуть менее, чем полностью. Они конечно работают, и в простейших случаях даже не так уж и медленно.
28 июн 18, 07:53    [21527044]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
hVostt
Member

Откуда:
Сообщений: 15626
Petro123
Сон Веры Павловны
SSIS
действительно.
Про ETL забыли.
Это его основная задача как у сабжа.


Это при условии, что там MS SQL.
28 июн 18, 07:55    [21527048]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
hVostt,
Конечно. У остальных нету AFAIK такой штуки.
28 июн 18, 07:58    [21527053]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
LR
Member

Откуда: 8P8C
Сообщений: 2372
hVostt
А триггеры, процедуры и прочая ересь, это однозначно бууэээ... Никогда так не делай. Никогда.

Почему? В данном случае (BulkCopy в N таблиц из 1 источника) это (вью+триггер) самое простое и эффективное решение, имхо конечно.
Вью можно сделать лишь "оберткой" для заливаемых данных, т.е., не основывая на каких-либо таблицах. Вот простецкий пример.
+ t-sql
if object_id('dbo.tblA') is not null drop table dbo.tblA
go
create table dbo.tblA(
 ID int not null constraint PK_tblA primary key
,name varchar(100) not null
)
go
if object_id('dbo.tblB') is not null drop table dbo.tblB
go
create table dbo.tblB(
 ID int not null constraint PK_tblB primary key
,name varchar(100) not null
)
go
if object_id('dbo.vw4BulkCopy') is not null drop view dbo.vw4BulkCopy
go
create view dbo.vw4BulkCopy
as
select 0 as [ID], cast('name1' as varchar(100)) as [name1], cast('name2' as varchar(100)) as [name2]
go
create trigger dbo.trInsVw4BulkCopy on dbo.vw4BulkCopy instead of insert
as
begin
	insert into dbo.tblA select [ID], [name1] from inserted
	insert into dbo.tblB select [ID], [name2] from inserted
end
go

+ c#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;

namespace ConsoleApp3
{
    class Program
    {
        static string connectionString = @"Data Source=.;Initial Catalog=testdb;Integrated Security=True;";
        static void Main(string[] args)
        {
            TestBulkCopy(1000);
            Console.ReadKey();
        }
        static void TestBulkCopy(int recordscount)
        {
            try
            {
                using (SqlConnection conn = new SqlConnection(connectionString))
                {
                    conn.Open();
                    using (SqlBulkCopy bulkCopy = new SqlBulkCopy(conn,
                        SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.FireTriggers | SqlBulkCopyOptions.UseInternalTransaction, null))
                    {
                        //bulkCopy.ColumnMappings.
                        bulkCopy.DestinationTableName = "dbo.vw4BulkCopy";
                        using (TestBulkCopyReader reader = new TestBulkCopyReader(recordscount))
                        {
                            bulkCopy.WriteToServer(reader);
                            Console.WriteLine($"Donecount={reader.Donecount - 1}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        public class TestBulkCopyReader : IDataReader
        {
            int _recordscount = 0;
            public int Donecount = 0;

            public TestBulkCopyReader(int recordscount)
            {
                _recordscount = recordscount;
            }

            #region IDataReader members
            public bool Read()
            {
                return ++Donecount <= _recordscount;
            }
            public object GetValue(int i)
            {
                switch (i)
                { 
                    case 0: return Donecount; //ID1
                    case 1: return string.Format($"row {Donecount} for table A");
                    case 2: return string.Format($"row {Donecount} for table B");
                    default: return null;
                }
            }
            public int FieldCount
            {
                get { return 3; }
            }
            public void Dispose()
            {
            }
            public string GetName(int i)
            {
                throw new NotImplementedException();
            }
            public int GetOrdinal(string name)
            {
                throw new NotImplementedException();
            }
            public void Close()
            {
                throw new NotImplementedException();
            }
            public int Depth
            {
                get { throw new NotImplementedException(); }
            }
            public DataTable GetSchemaTable()
            {
                throw new NotImplementedException();
            }
            public bool IsClosed
            {
                get { throw new NotImplementedException(); }
            }
            public bool NextResult()
            {
                throw new NotImplementedException();
            }
            public int RecordsAffected
            {
                get { throw new NotImplementedException(); }
            }
            public bool GetBoolean(int i)
            {
                throw new NotImplementedException();
            }
            public byte GetByte(int i)
            {
                throw new NotImplementedException();
            }
            public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
            {
                throw new NotImplementedException();
            }
            public char GetChar(int i)
            {
                throw new NotImplementedException();
            }
            public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
            {
                throw new NotImplementedException();
            }
            public IDataReader GetData(int i)
            {
                throw new NotImplementedException();
            }
            public string GetDataTypeName(int i)
            {
                throw new NotImplementedException();
            }
            public DateTime GetDateTime(int i)
            {
                throw new NotImplementedException();
            }
            public decimal GetDecimal(int i)
            {
                throw new NotImplementedException();
            }
            public double GetDouble(int i)
            {
                throw new NotImplementedException();
            }
            public Type GetFieldType(int i)
            {
                throw new NotImplementedException();
            }
            public float GetFloat(int i)
            {
                throw new NotImplementedException();
            }
            public Guid GetGuid(int i)
            {
                throw new NotImplementedException();
            }
            public short GetInt16(int i)
            {
                throw new NotImplementedException();
            }
            public int GetInt32(int i)
            {
                throw new NotImplementedException();
            }
            public long GetInt64(int i)
            {
                throw new NotImplementedException();
            }
            public string GetString(int i)
            {
                throw new NotImplementedException();
            }
            public int GetValues(object[] values)
            {
                throw new NotImplementedException();
            }
            public bool IsDBNull(int i)
            {
                throw new NotImplementedException();
            }
            public object this[string name]
            {
                get { throw new NotImplementedException(); }
            }
            public object this[int i]
            {
                get { throw new NotImplementedException(); }
            }
            #endregion
        }
    }
}
28 июн 18, 09:47    [21527287]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
Petro123
Member

Откуда: Загрузочный сектор Москвы (AutoPOI.ru)
Сообщений: 38643
LR
Почему?
ну, он чуть преувеличил.
Все варианты одинаковы).

LR
Вот простецкий пример.

Права на бд должны быть выше чем одычно.
В продакшене у заказчика могут не дать.
Как вариант плюсов. Минусов.
28 июн 18, 10:04    [21527368]     Ответить | Цитировать Сообщить модератору
 Re: BulkCopy в N таблиц из 1 источника  [new]
hVostt
Member

Откуда:
Сообщений: 15626
LR
Почему? В данном случае (BulkCopy в N таблиц из 1 источника) это (вью+триггер) самое простое и эффективное решение, имхо конечно.


Вью, которое на самом деле не вью, а генерация набора колонок. Триггер, который на самом деле выполняет задачи процедуры. Костыль на костыле. С определённого угла зрения, конечно может выглядеть, как "трюк". Тут уже действительно ИМХО ))

Простое, это процедура, как предложил Алексей К.

Эффективное? Нет. Ни разу, я вас умоляю.

Ну и попробуйте булк в свою вью, посмотрим-с, как это у вас заработает.
28 июн 18, 10:23    [21527468]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / WinForms, .Net Framework Ответить