Создание хранимых процедур, которые могут работать с разными таблицами - PullRequest
3 голосов
/ 04 июня 2011

Мне нужно использовать одни и те же хранимые процедуры для многих таблиц с одинаковой структурой в моей БД. Это данные, загруженные от клиентов, с одной таблицей / клиентом, и необходимо выполнить расчеты / проверки данных перед их загрузкой в ​​наш DataWarehouse.

Пока что это варианты и проблемы, которые я обнаружил, и я ищу лучший шаблон / подход.

  1. Создайте представление, которое указывает на столик хочу обработать, ИП затем поговорите с этим мнением. Это работает хорошо (особенно когда я работал как создавать представления "автоматически" по их столбцам). Но представление может использоваться только с одной таблицей за один раз, заставляя систему иметь дело с одним клиентом одновременно.

  2. Использование динамического sql в каждом SP - делает SP гораздо сложнее читать / отлаживать и по этим причинам имеет было исключено

  3. Создание секционированного представления по все таблицы, а затем использовать параматизированная табличная функция для возврата только данные, которые нас интересуют - ах, но тогда я не могу обновить данные так как функция возвращает таблицу, может использоваться только для выбора

  4. Использовать динамический sql внутри функции (не может быть сделано), чтобы создать представление (что также не может быть сделано) .... дать до
  5. Внутри SP создайте временную таблицу с над целевой таблицей, используя динамический sql, но потом временная таблица существует только в сеансе, который выполняется динамический sql не «родитель» сеанс, который работает SP ... сдаться
  6. Создать глобальную временную таблицу, используя динамический SQL, чтобы избежать проблемы области из 5, а затем запустить SP против глобальная временная таблица. Все еще сталкиваюсь одиночный выпуск клиента.
  7. Создайте вид как в 1 в пределах транзакции, а затем запустить все SP а потом коммит - отлично работает на одного пользователь, но любые другие теперь заблокированы пытаясь создать новый взгляд на то же имя
  8. Использовать временное представление ... невозможно в Т / SQL * 1 026 *
  9. Переместить весь код в .Net - но у нас есть проблемы с окружающей средой, где tsql намного проще разместить / запустить

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

Ответы [ 5 ]

11 голосов
/ 07 июня 2011

Возможно, ваш подход неправильный, через некоторое время я углублюсь в детали, но кажется, что ваша проблема может быть решена с помощью SSIS

- Обновленный ответ :

Во-первых, общая картина:

Наиболее доступным способом динамической обработки таблиц является использование сценария вместо хранимой процедуры.Если вы хотите, чтобы доступ к таблице выбирался случайным образом, вы, безусловно, не будете использовать никаких преимуществ производительности хранимых процедур, то есть планов выполнения.Сценарий SQL можно легко обновить, чтобы он указывал на одну таблицу во время выполнения, используя заполнители и заменяя ее перед выполнением.

Сценарий можно загрузить из файловой системы, переменной, текстового столбца в таблице и т. Д. ЗагрузкаПроцесс заключается в чтении содержимого скрипта в строковую переменную.Этот шаг выполняется один раз.

Следующим шагом является этап подготовки.Этот шаг будет выполнен для каждой таблицы, которая будет обработана.Основная задача этого шага - заменить заполнители таблицы текущей обрабатываемой таблицей.Также возможно установить значения параметров как любой параметр, который вам может понадобиться передать в sp, который вы уже написали.

Последний шаг - это выполнение скрипта.Так как уже загружен в переменную и заполнители были установлены на текущее имя таблицы, вы можете безопасно вызвать ExecuteSQLTask с переменной sql в качестве входных данных.Этот процесс, конечно, происходит для каждой таблицы, которую вы хотите обработать.

Хорошо.Теперь давайте посмотрим на это в действии.

Это пример модели базы данных:

CREATE TABLE [dbo].[t_n](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [name] [varchar](50) NOT NULL,
  [start] [datetime] NULL,
  CONSTRAINT [PK_t_n] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]

, где t_n представляет любую таблицу (t_1, t_2, t_3 и т. Д.).

Это ваша текущая хранимая процедура:

CREATE PROCEDURE SpProcessT_n 
AS
BEGIN
    SET NOCOUNT ON;
    SELECT * FROM [t1]; 
END
GO

Теперь, преобразуйте эту хранимую процедуру в скрипт Sql, поместив вместо имени таблицы заполнитель

    SET NOCOUNT ON;
    SELECT * FROM [$table_name];

Я хочу сохранить это вфайл .sql в файловой системе, чтобы максимально упростить POC.

Затем создайте пакет служб SSIS следующим образом:

Basic SSIS Package

Это настройкиЯ выбираю настройку цикла: enter image description here

И это способ, которым вы можете назначить имя таблицы для переменной с соответствующим именем _table_name_ enter image description here

Это настройка скриптаЗдесь вы обнаружите, что переменная _table_name_ имеет доступ только для чтения, а новая переменная с именем SqlExec имеет доступ для чтения / записи:

enter image description here

И это ее основная функция:

    public void Main()
    {
        String Table_Name = Dts.Variables["table_name"].Value.ToString();
        String SqlScript;
        Regex reg = new Regex(@"\$table_name", RegexOptions.Compiled);
        using (var f = File.OpenText(@"c:\sqlscript.sql")) {
            SqlScript = f.ReadToEnd();
            f.Close();
        }
        SqlScript = reg.Replace(SqlScript, Table_Name);
        Dts.Variables["SqlExec"].Value = SqlScript;
        Dts.TaskResult = (int)ScriptResults.Success;
    }

Вы можете заметить, что переменная Dts SqlExec содержитs SQL-скрипт, который будет выполнен.Теперь вы можете установить следующие параметры в вашем ExecuteSqlTask:

enter image description here

Успешно протестировано в MSSQL 2008, если вы вставите вставку в файл скрипта, вы увидите новые строки в каждой таблице.

Надеюсь, это поможет!

2 голосов
/ 08 июня 2011

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

Вы действительно можете рассчитать время запуска этого пакета. Если он по-прежнему удивительно быстр, скажем, в течение 30 минут, вы можете делать ставки каждые несколько часов, например, в начале рабочего дня, обеденном перерыве и конце дня. Таким образом, вы можете получить почти свежие данные для запроса.

1 голос
/ 10 июня 2011

Я бы не стал делать это с SQL.То, что вы описываете, звучит как традиционная ситуация ETL .

Поскольку все таблицы клиентов совпадают, я бы создал таблицу в хранилище данных со всеми столбцами из таблицы клиента., столбец суррогатного ключа и идентификатор типа.У вас есть возможность создать «промежуточную» таблицу, в которой будут только данные во время процесса ETL или только работа с одной «живой» таблицей.Я бы создал промежуточный стол.

Затем в пакете служб SSIS (не волнуйтесь, вы все еще можете планировать из агента SQL Server, он не полностью покинул сервер БД), запустить процесс ETL ...

E (xtract): скопируйте данные из вашего источника в промежуточную таблицу в хранилище данных.Скорее всего, вы захотите использовать подпакет в цикле foreach и изменить имя таблицы, которую вы хотите обработать из внешнего хранилища (большинство людей скажут, что положите это на склад, но решать вам).

T (преобразование): запустите вычисления / проверки, о которых вы говорили, но сделайте это для всего набора ...

L (oad): скопируйте его в свой реальный в хранилище данных.

Есть пара вещей, которые я бы НЕ сделал.1. Измените данные в исходной таблице.2. Попробуйте сделать это в t-sql.Это просто не то, в чем хорош tsql.

Если вам нужно больше подробностей об этом подходе, я, вероятно, задам вопрос с некоторыми тегами Business Intelligence.Я буду путешествовать в течение следующей недели или около того, но я постараюсь просмотреть комментарии, чтобы прояснить что-нибудь, если понадоблюсь.

1 голос
/ 07 июня 2011

Написать разделенное представление, включая имена таблиц?

SELECT 'TableName', t.* FROM TableName t
UNION ALL 
SELECT 'TableName2', t.* FROM TableName2 t

Затем написать один вместо триггера, который использует динамический SQL для записи (меньше тестов, связанных с использованием динамического SQL, потому что вы просто пишетея думаю, простые операции CRUD для всех таблиц)

0 голосов
/ 07 июня 2011

Я вполне уверен, что стандартным способом решения этой проблемы является использование динамического SQL в каждом sp (ваш вариант 2), что уже было исключено.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...