Archives pour la catégorie T-SQL

SQL Server РComment appeler une proc̩dure stock̩e dans une vue ou fonction avec un serveur li̩ r̩cursif et OPENQUERY

Vous le savez peut être que SQL Server ne laisse pas passer les commandes CREATE VIEW basé sur les résultats des procédures stockées. Des fois ceci peut être pénalisant!

Imaginons une requête qui boucle sur chaque base de données d’une instance et qui insère les résultats dans une table temporaire de type #table.

CREATE TABLE #DB_NAMES (DB_NAMES VARCHAR(255))

EXEC sys.sp_MSforeachdb 'USE ?
INSERT INTO SELECT '
'?'''

SELECT * FROM #DB_NAMES

DROP TABLE #DB_NAMES

Ce code ne peut pas être incorporé dans une vue à cause du fait qu’il se base sur une #table. Vous pouvez, cependant créer une procédure stockée avec la requête.

USE [VOTRE_BASE]
GO

SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [dbo].[LOOPBACKTEST]
AS

CREATE TABLE #DB_NAMES (DB_NAMES VARCHAR(255))

EXEC sys.sp_MSforeachdb 'USE ?
INSERT INTO SELECT '
'?'''

SELECT * FROM #DB_NAMES

DROP TABLE #DB_NAMES

Maintenant, qu’est-ce qui se passe si on veut requêter sur les résultats de la procédure stockée? C’est là le problème. La réponse se trouve dans la clause OPENQUERY. Il s’agit d’une feinte/workaround mais SQL Server laisse passer des requêtes sur les résultats des requêtes sur des serveurs liés. Mais ceci est prévu pour marcher avec des serveurs distants non? Pas forcément! Vous pouvez créer ce que l’on appelle un serveur lié récursif.

EXEC sp_addlinkedserver @server = N'LOOPBACK',
    @srvproduct = N' ',
    @provider = N'SQLNCLI',
    @datasrc = N'VOTRE NOM D''INSTANCE SQL SERVER ICI',
    @catalog = N'VOTRE_BASE'

Une fois terminé vous pouvez requête sur les résultats de votre procédure stockée avec la syntaxe suivant :

SELECT  *
FROM    OPENQUERY([LOOPBACK], '
EXEC [YOUR_DATABASE].[dbo].[LOOPBACKTEST]'
)

Et vous pouvez même créer une vue qui se base sur la requête pour pouvoir requête souplement sur les résulats.

CREATE VIEW [dbo].[LOOPBACKTESTVIEW]
AS
SELECT  *
FROM    OPENQUERY([LOOPBACK], '
EXEC [VOTRE_BASE].[dbo].[LOOPBACKTEST]'
)
SELECT  *
dbo.LOOPBACKTESTVIEW
WHERE DB_NAMES LIKE 'VOTRE_%'

Sachez que ceci est simplement un exemple inutile mais vous pouvez faire ce que vous voulez dans la première requête afin de créer une contrôle introspective par exemple. Tout est possible ;)

SQL Server – Comment visualiser très facilement l’espace disque restant à partir de SSMS

Des fois il est nécessaire de connaitre l’espace disque d’un serveur quand on n’a pas de connexion de bureau à distance sur la machine hôte. On peut imaginer des situations qui nécessitent la mise en places des indexes ou de faire des grosses transactions qui pourraient faire grossir la tempdb sans avoir un accès sur le serveur.

Il existe un moyen très simple de le faire en une ligne de code!!

EXEC master.sys.xp_fixeddrives

Cette magnifique procédure stockée retourne une liste de tous les disques ainsi que leur espace disque restant.

On pourra même imaginer une mise en place industrialiser d’un système qui nécessite une contrôle d’espace disque avant de se lancer dans sa transaction. Avec cette procédure stockée il n’a pas de limit! En dehors de la taille de votre disque dur ;)

SQL Server – Sp_MSForEachDB une façon simple de requêter toutes les bases de données d’une instance

De temps en temps il est nécessaire d’exécuter une requête simple sur toute les bases de données d’une instance SQL Server.

Jusqu’à il n’y a pas très longtemps j’ai toujours écrit des requêtes très complexes qui utilisé des CURSOR et des tables temporaires afin d’effectuer le travail voulu.

Et après j’ai trouvé la procédure stockée non-documentée Sp_MSForEachDB.

Pour expliquer simplement : cette procédure stockée laisse l’utilisateur coller un variable ? dans une requête qui prend la place de la base de données et elle exécute la même requête pour chaque base attachée à l’instance SQL Server.

Voici une petite requête pour montrer comment ça fonctionne :

EXEC sys.sp_MSforeachdb 'USE ?;
SELECT DB_ID(), DB_NAME()'

Vous devriez voir une like de toute les bases de données attachées à votre instance par identifiant et nom.

Vous allez voir que le moteur retourne plusieurs jeux de résultats dans le fenêtre SSMS. C’est à cause du fait que sp_MSforeachdb itère sur chaque base. Ce n’est pas une transaction unique.

Pour l’utilisateur avancé qui aimerait industrialiser l’utilité de cette procédure stockée vous pouvez simplement créer une table temporaire qui stocke les résultats et ensuite vous allez pouvoir requête sur cette table à peu plus loin dans le code T-SQL.

Voici un exemple que j’ai utilisé pour contrôler le taux de fragmentation de toutes les indexes fragmentés de plus que 5%:

CREATE TABLE dbo.#FragTab
(DB_Name VARCHAR(100),
[Schema] VARCHAR(50),
[TABLE] VARCHAR(200),
[INDEX] VARCHAR(200),
avg_fragmentation_in_percent FLOAT,
REBUILD_Necessary BIT,
REORGANISE_Necessary BIT)

EXEC sys.sp_MSforeachdb
'
USE ?;
INSERT INTO #FragTab
SELECT
DBs.name as '
'DB_Name'',
dbschemas.[name] as '
'Schema'',
dbtables.[name] as '
'Table'',
dbindexes.[name] as '
'Index'',
indexstats.avg_fragmentation_in_percent,
CASE WHEN indexstats.avg_fragmentation_in_percent > 30 THEN 1 ELSE 0 END as REBUILD_Necessary,
CASE WHEN indexstats.avg_fragmentation_in_percent BETWEEN 5 AND 30 THEN 1 ELSE 0 END as REORGANISE_Necessary
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS indexstats
INNER JOIN sys.tables dbtables on dbtables.[object_id] = indexstats.[object_id]
INNER JOIN sys.schemas dbschemas on dbtables.[schema_id] = dbschemas.[schema_id]
INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id]
AND indexstats.index_id = dbindexes.index_id
LEFT OUTER JOIN sys.databases as DBs ON DBs.database_id = indexstats.database_id
WHERE indexstats.database_id = DB_ID()
AND indexstats.avg_fragmentation_in_percent > 5
AND dbindexes.name IS NOT NULL'


SELECT * FROM #FragTab
DROP TABLE #FragTab