kun suoritan seuraavan komentosarjan, se toimii hyvin:

declare @temp table ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); INSERT @temp exec sp_msforeachdb @command1="use ?; Exec sp_helpfile;" 

mutta kun Käytän omaa sp_foreachdb-menettelytani, lähdekoodi on tässä linkissä:

Luotettavampi ja joustavampi sp_MSforeachdb

declare @temp table ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); INSERT @temp exec sp_foreachdb @command="use ?; Exec sp_helpfile;" 

Saan poikkeuksen (huomaa, että olen lisännyt poikkeusten käsittelyn kyseiseen menettelyyn)

--EXCEPTION WAS CAUGHT-- THE ERROR NUMBER:8164 SEVERITY: 16 STATE: 1 PROCEDURE: sp_foreachdb LINE NUMBER: 165 ERROR MESSAGE: An INSERT EXEC statement cannot be nested. ------------------------------------ the sql ------------------------------------ SELECT name FROM sys.databases WHERE 1=1 AND state_desc = N"ONLINE" AND is_read_only = 0 Msg 16916, Level 16, State 1, Procedure sp_foreachdb, Line 239 A cursor with the name "c" does not exist. Msg 16916, Level 16, State 1, Procedure sp_foreachdb, Line 240 A cursor with the name "c" does not exist. (0 row(s) affected) 

Kommentit

  • En ’ ole varma, miksi ’ käytät tätä sekavaa menetelmä. Miksi et kysy vain sys.master_files?
  • @Nic huomautti hyvin, olen kuitenkin juuri käyttänyt sp_helpfile-esimerkkiä. tosielämässä se on yksi omista tallennetuista menettelyistämme, joita kutsun

Vastaus

Lähdekoodi Aaronille ”s sp_foreachdb sisältää seuraavan rivin:

INSERT #x EXEC sp_executesql @sql;

virhesanoma:

INSERT EXEC -käskyä ei voida sisäkkäin.

Joten alla oleva tällainen koodi ei ole kelvollinen, koska se pesii INSERT xxx EXEC xxx -koodia.

INSERT @temp exec sp_msforeachdb @command1="use ?; Exec sp_helpfile;" 

Kommentit

  • @marcellomiorelli Mielestäni se vaatii suuren muutoksen Aaronin ’ SP: hen dynaamisen SQL: n poistamiseksi. Tämä edellyttäisi todennäköisesti lisätoiminto.

Vastaa

Yhteyden muodostaminen omaan palvelimeen hajautettujen kyselymenetelmien avulla tekisi tempun, jos sp_foreachdb palauttaisi yhden tulosjoukon.

create table #temp ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); insert into #temp select * FROM OPENROWSET("SQLNCLI", "SERVER=****;UID=****;PWD=****", " exec sp_foreachdb @command="" Exec ?..sp_helpfile;"" WITH RESULT SETS ((name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255))); ") select * from #temp 

kyselyn yläpuolella w huonosti palauttaa vain sp_foreachdb-suorituksen ensimmäisen tulosjoukon. mutta alla oleva kysely palauttaa kaikkien tietokantojen tulokset yhdessä tulosjoukossa.

create table #temp ( name varchar(255), field varchar(255), filename varchar(255), filegroup varchar(255), size varchar(255), maxsize varchar(255), growth varchar(255), usage varchar(255) ); exec sp_foreachdb @command="INSERT INTO #temp Exec ?..sp_helpfile;" select * from #temp 

Vastaa

Voit yrittää mukauttaa Aaronin SP: tä päästä eroon dynaamisen osan. Dynaamisen osan on tarkoitus rakentaa kysely, joka lukee vain tietokannan nimet kohdasta sys.databases toimitettujen argumenttien perusteella. Dynaaminen SQL valitaan tekemään kyselystä tehokkain – Kun otetaan huomioon erityistarpeesi, jotkut uhraukset saattavat olla kunnossa.

Väitän kuitenkin, että suorituskyky ei ehkä kärsi paljon alla tarjoamastani uudelleenkirjoittamisesta, koska sys.databases järjestelmänäkymässä ei yleensä ole kovin monta riviä, mutta joka tapauksessa voit lisätä lopuksi OPTION (RECOMPILE). Vaikka se voikin olla hidasta, tosin todennäköisesti loppujen lopuksi melko ruma, mitä voin luvata.

Uudelleen kirjoittamismenetelmä on seuraava. Aaronin menettely rakentaa kyselyn toistuvan mallin avulla, jossa parametriarvo tarkistetaan ja , tuloksen perusteella ylimääräinen kysely lisätään dynaamiseen kyselyyn, näin:

SET @sql = N"SELECT name FROM sys.databases WHERE 1=1" + CASE WHEN some_condition1 THEN "AND some_filter1" ELSE "" END + CASE WHEN some_condition2 THEN "AND some_filter2" ELSE "" END + ... 

Näin kirjoitat sen uudestaan:

SELECT name FROM sys.databases WHERE 1=1 AND (some_filter1 OR opposite_of_some_condition1) AND (some_filter2 OR opposite_of_some_condition2) AND ... OPTION (RECOMPILE); 

Esimerkiksi @system_only ohjaa, sisällytetäänkö database_id IN (1,2,3,4) -suodatin, kuten tämä:

SET @sql = N"SELECT name FROM sys.databases WHERE 1=1" + CASE WHEN @system_only = 1 THEN " AND database_id IN (1,2,3,4)" ELSE "" END 

Uudelleen kirjoitettu kysely parametrisoidaan tällä tavalla:

SELECT name FROM sys.databases WHERE 1=1 AND (database_id IN (1,2,3,4) OR @system_only <> 1) -- or: @system_only = 0 

Käytä tuloksena olevaa kyselyä kohdistin suoraan sen sijaan, että

 SELECT CASE WHEN @suppress_quotename = 1 THEN db ELSE QUOTENAME(db) END FROM #x ORDER BY db 

Kuten voidaan nähdä, viimeisen kosketuksen tulisi siirtyä SELECT-osaan, jossa yksinkertainen korvataan sanalla

 SELECT CASE WHEN @suppress_quotename = 1 THEN name ELSE QUOTENAME(name) END 

Voit tietysti päästä eroon myös #x -taulukkoa ei enää tarvita SP: ssä.

Viimeinen huomautus koskee tiettyä komentosarjaa, jonka aiot suorittaa kussakin tietokannassa. Voit

@command1="use ?; Exec sp_helpfile;" 

sijasta vain

@command1="Exec ?..sp_helpfile;" 

vastata

Kirjoitin korvaavan osan, jolla on useita parannuksia alkuperäiseen sp_foreachdb , mukaan lukien kyky pesiä. Uudempaa, ensisijaista menettelyä kutsutaan nimellä sp_ineachdb ( osa 1 / osa 2 ), ja se on saatavana myös osana Brent Ozarin ”s First Responder Kit .

Tausta täällä :

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *