2009-10-15 2 views
5

Я работаю над следующим обновлением для StackQL.Могу ли я установить схему по умолчанию для хранимой процедуры?

Одна вещь, которую я хочу сделать, - это возможность запросить несколько выпусков. Поэтому, когда я загружал октябрьские данные, например, я не удалял старую сентябрьскую базу данных. Он все еще там. На самом деле, вы даже можете все еще запросить его, включив имя базы данных, как это:

select top 10 * from SO_Sept09..Posts 

Это будет еще более важно, как они начинают предоставлять данные для ServerFault и суперпользователя.

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

Запросы на StackQL в конце концов просто передается функции exec() так:

exec(@QueryText) 

Что я могу сделать что-либо в хранимой процедуре или вставляться в строку QueryText (ала USE [DatabaseName]) для установки по умолчанию схема, используемая в запросе?

+0

Отличный вопрос! – RBarryYoung

ответ

3

Помимо изменения @QueryText себя, единственное, что я могу думать о том, пользовательская схема по умолчанию:

ALTER USER SO_Sept09_Reader WITH DEFAULT_SCHEMA = SO_Sept09 

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

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

+0

Добавление заполнитель схемы, безусловно, не является вариантом. Сайт позволяет любому писать и запускать sql-запрос снова с дампа общих данных StackOverflow, и они могут писать практически все. Изменение пользователя также отсутствует, так как это вызовет проблемы с параллелизмом. Но это дает мне идею, возможно, иметь несколько пользователей и выбрать строку соединения на лету. –

+0

Да, это то, что я предлагал; один или несколько (статических) пользователей на схему; переключать пользователей (путем соединения с соответствующими строками соединения) на лету. –

1

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

Примечание это не работает с динамическим SQL внутри такой SP:

CREATE PROCEDURE schema_a.SP 
    @somesql AS varchar(MAX) 
AS 
BEGIN 
    EXEC (@somesql) 
END 

CREATE PROCEDURE schema_b.SP 
    @somesql AS varchar(MAX) 
AS 
BEGIN 
    EXEC (@somesql) 
END 

не будет работать, так как близость схемы теряется внутри EXEC.

В то время как это:

CREATE PROCEDURE schema_a.SP 
AS 
BEGIN 
    SELECT * FROM tbl -- Will use schema_a.tbl first 
END 

CREATE PROCEDURE schema_b.SP 
AS 
BEGIN 
    SELECT * FROM tbl -- Will use schema_b.tbl first 
END 

работает отлично.

Аналогично:

EXEC ('EXEC schema_a.SP') 

, очевидно, работать нормально.

+0

Все еще kludge, но мне это нравится лучше, чем создание дополнительных пользователей. –

+0

Не работает. Когда я попробовал, он поднял стол в dbo. –

+0

Я бы пошел с EXECUTE AS, как в ответ RBArryYoung, так как вы уже используете динамический SQL. Причина, по которой схожесть схемы не работает для вас, заключается в том, что после того, как вы нажмете на exec, вы теряете контекст схемы из SP, который вызывает exec, точно так же, как он теряет практически все остальное. –

0

Неиспользованный, но: вы могли бы объединить данные разных схем в один вид и добавить столбец, вызывающий имя схемы?

CREATE VIEW AllPosts AS 
    SELECT Data1, Data2, 'Sept09' AS Partition FROM SO_Sept09..Posts 
    UNION ALL 
    SELECT Data1, Data2, 'Oct09' AS Partition FROM SO_Oct09..Posts 
    ... 

SELECT * FROM AllPosts WHERE Partition = 'Sept09' 
SELECT * FROM dbo.AllPosts('Sept09') -- if use table-valued function instead 
+0

Это мысль, но это сильно сломало мое индексирование. –

+0

Вы можете индексировать представления, но с целым рядом оговорок. http://msdn.microsoft.com/en-us/library/dd171921.aspx http://msdn.microsoft.com/en-us/library/ms191432.aspx –

11

Есть несколько способов сделать это в разных местах здесь, но не совсем.Способ сделать это:

  1. сделать уникальный Логин & пользователя для каждой схемы

  2. сделать этим пользователям владельцев каждой другой схеме.

  3. Установите для каждой такой схемы пользователя такую ​​схему, которая им принадлежит.

  4. Используйте синтаксис EXECUTE ('sql commands') AS USER = 'schema-owner' для выполнения ваших SQL-команд в контексте этой схемы по умолчанию.

Следующий сценарий демонстрирует это:

--====== Create the Login for the User: 
CREATE LOGIN [UserTest1] WITH PASSWORD='whatever', DEFAULT_DATABASE=[TestUsers], DEFAULT_LANGUAGE=[us_english] 
GO 

--====== Make a User for the Login: 
CREATE USER [UserTest1] FOR LOGIN [UserTest1] 
GO 

--====== Make a Schema owned by the User and default to it: 
--  (I assume that you already have the schemas) 
CREATE SCHEMA [UserTest1] AUTHORIZATION [UserTest1] 
GO 
ALTER USER [UserTest1] WITH DEFAULT_SCHEMA=[UserTest1] 
GO 

--====== Make a sProc in dbo 
CREATE PROCEDURE [dbo].[TestSchema_Exec] AS 
    SELECT 'executing in schema [dbo]' 
GO 
--====== Make a similar sProc in New Schema 
CREATE PROCEDURE [UserTest1].[TestSchema_Exec] AS 
    SELECT 'executing in schema [UserTest1]' 
GO 

--========= Demonstrate that we can switch Default Schemas: 
EXEC('TestSchema_Exec') 

EXEC('TestSchema_Exec') AS USER = 'UserTest1' 
0

Хорошо, у меня есть новый способ сделать это, что могло бы работать немного лучше для меня. Это вариант моего комментария к ответу Майкла Петротты:

Но это дает мне идею, возможно, иметь несколько пользователей и выбрать строку соединения на лету.

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