2009-10-15 1 views
5

Sto lavorando al prossimo aggiornamento per StackQL.Posso impostare uno schema predefinito all'interno di una stored procedure?

Una cosa che voglio fare è la possibilità di eseguire query su più versioni. Così, quando ho caricato i dati di ottobre, ad esempio, non ho cancellato il vecchio database di settembre. È ancora là fuori. In realtà, si può anche ancora ricerca si includendo il nome del database in questo modo:

select top 10 * from SO_Sept09..Posts 

questo sarà ancora più importante in cui iniziano fornire dati per ServerFault e SuperUser.

Ma non mi piace avere un sacco di database disponibili per supportare questo. Preferirei piuttosto mettere tutti i dati nello stesso database e separare ciascun insieme distinto nel proprio schema. Ma per rendere ciò possibile, devo essere in grado di impostare uno schema predefinito come parte della stored procedure che esegue la query, in base a un parametro passato alla stored procedure che indica quale database l'utente ha selezionato da un futuro elenco a discesa per apparire nella barra degli strumenti.

query a StackQL sono alla fine solo passati alla funzione exec() in questo modo:

exec(@QueryText) 

C'è qualcosa che posso fare sia nella stored procedure o anteporre alla stringa QUERYTEXT (ala USE [DatabaseName]) per impostare il valore predefinito schema utilizzato in una query?

+0

Ottima domanda! – RBarryYoung

risposta

3

Altro che modifica @QueryText stessa, l'unica cosa che posso pensare è schema predefinito di un utente:

ALTER USER SO_Sept09_Reader WITH DEFAULT_SCHEMA = SO_Sept09 

... e poi collegare come un utente diverso per ogni schema che si desidera utilizzare. Hackity hack.

Ma se la query è comunque costruita dinamicamente (e sono sicuro che sai perché spesso non è una grande idea), potrebbe essere più semplice aggiungere un segnaposto dello schema al testo della query e passare il nome dello schema lungo con la query a una funzione di sostituzione.

+0

L'aggiunta di un segnaposto dello schema non è sicuramente un'opzione. Il sito consente a chiunque di scrivere ed eseguire una query sql nuovamente il dump di dati pubblici StackOverflow, e potrebbero scrivere qualsiasi cosa. Anche l'alterazione dell'utente è fuori controllo, poiché ciò causerebbe problemi di concorrenza. Ma mi dà l'idea di avere forse diversi utenti e scegliere la stringa di connessione al volo. –

+0

Sì, il secondo è quello che stavo suggerendo; uno o più utenti (statici) per schema; cambiare utente (collegandosi con stringhe di connessione corrispondenti) al volo. –

1

Un'altra possibilità è di generare copie di ogni SP in ogni schema, il nome di tabella non modificato in un SP fa riferimento alle tabelle nello stesso schema.

Nota questo non funziona con SQL dinamico all'interno di un tale 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 

non funzionerà, perché l'affinità schema si perde all'interno del EXEC.

Mentre questo:

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 

funziona bene.

Analogamente:

EXEC ('EXEC schema_a.SP') 

sarebbe ovviamente funzionare bene.

+0

Ancora un kludge, ma mi piace meglio che creare altri utenti. –

+0

Non ha funzionato. Ha preso il tavolo in dbo quando l'ho provato. –

+0

Vorrei andare con EXECUTE AS come nella risposta di RBArryYoung poiché stai già utilizzando SQL dinamico. Il motivo per cui l'affinità dello schema non funziona per te è che una volta che si preme l'exec, si perde il contesto dello schema dall'SP che chiama exec, proprio come si perde praticamente tutto il resto. –

0

Non tentato, ma: è possibile combinare i dati dei diversi schemi in un'unica vista e aggiungere una colonna che richiama il nome dello schema?

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

È un pensiero, ma romperebbe un sacco della mia indicizzazione. –

+0

È possibile indicizzare le visualizzazioni, sebbene con tutta una serie di avvertimenti. http://msdn.microsoft.com/en-us/library/dd171921.aspx http://msdn.microsoft.com/en-us/library/ms191432.aspx –

11

ci sono pezzi di come fare questo in vari luoghi qui, ma non del tutto.Il modo per farlo è:

  1. Fai un unico utente di accesso & per ogni schema

  2. Effettuare questi utenti i proprietari di ogni schema diverso.

  3. Impostare ciascuno schema predefinito di tale utente come lo schema di loro proprietà.

  4. Utilizzare la sintassi EXECUTE ('sql commands') AS USER = 'schema-owner' per eseguire i comandi SQL nel contesto di quello schema predefinito.

Il seguente script dimostra questo:

--====== 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

Va bene, ho un nuovo modo per fare ciò che potrebbe funzionare un po 'meglio per me. È una variante del mio commento alla risposta di Michael Petrotta:

Ma mi dà l'idea di avere forse più utenti e scegliere la stringa di connessione al volo.

Quello che farò è avere un solo utente per eseguire queste query, ma sostituirò la stringa di connessione al volo per specificare il catalogo iniziale corretto.