IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Administration SQL Server Discussion :

Obliger la création de table sur un filegroup spécifique


Sujet :

Administration SQL Server

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut Obliger la création de table sur un filegroup spécifique
    Bonjour,
    Voici mon besoin : Je souhaite, pour certains users, ajouter des droits de création de table. Mais uniquement sur un filegroup particulier qui n'est pas celui par défaut .
    Lorsque l'on fait un CREATE TABLE , si le filegroup n'est pas spécifié il se place sur celui par défaut. Je souhaite empêcher cela pour ces users.

    En résumé, Si le user crée une table ,ça la crée dans un autre filegroup de manière implicite.
    L'objectif est d'empêcher l'oubli de leur part d'ajouter un 'ON [mon_filegroup]' à chaque création de table, un oubli est vite arrivé.
    Pourquoi? car le filegroup PRIMARY (qui est celui par défaut) n'a pas un gros espace de stockage.

    J'ai cherché sur le net, en vain.

    J'ai trouvé cet article : https://www.brentozar.com/archive/20...ed-management/
    qui semble dire que ce n'est pas faisable.

    Est-ce possible par exemple via un database trigger?

  2. #2
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Il suffit de créer un FILEGROUP bidon "default" et "readonly".

    Du coup quand un utilisateur tente de créer une table dedans (comportement par défaut), ça lui pète au nez
    On ne jouit bien que de ce qu’on partage.

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut
    J'ai déjà un default filegroup, le "PRIMARY".
    J'ai reçu un nouveau disque spécifique pour mon besoin. Mais je ne veux pas qu'il soit celui par défaut.

  4. #4
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Essaie de suivre la vidéo quand même :

    https://youtu.be/fOnmo9bao-o
    On ne jouit bien que de ce qu’on partage.

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut
    Ah je n'avais pas bien compris ta remarque . Oui cela pourrait être une solution effectivement.
    Mais je ne peux l'appliquer car certains processus automatiques existant doivent faire des DROP/CREATE table.
    Si je fais cette modif , je vais avoir un bon retour de manivelle , je devrais adapter tous les codes (rajouter ON[PRIMARY]). Trop compliqué.
    Merci quand même.

  6. #6
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Bonjour,

    Voici un début, car je n'ai pas couvert tous les cas possibles, par exemple :

    • les contraintes de clé primaire et d'unicité qui sont supportées par des index, et pour lesquels on peut spécifier le groupe de fichiers dans lequel on souhaite que les index soient placés
    • les tables optimisées en mémoire (Hekaton)
    • ...


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    ALTER TRIGGER TR_IOF_CREATE_TABLE
    	ON DATABASE
    FOR CREATE_TABLE
    AS
    BEGIN
    	SET NOCOUNT ON
     
    	DECLARE @x xml = EVENTDATA()
     
    	DECLARE @sql_recreate_table nvarchar(max)
    		, @sql_drop_table nvarchar(max)
    		, @table_to_drop varchar(1000)
     
    	SELECT	@sql_recreate_table = N.n.value('(./TSQLCommand/CommandText)[1]', 'varchar(max)')
    		, @sql_drop_table = 'DROP TABLE ' + N.n.value('(./SchemaName[1])', 'varchar(128)')
    			+ '.' + N.n.value('(./ObjectName[1])', 'varchar(128)')
    	FROM	@x.nodes('/EVENT_INSTANCE') AS N(n)
     
    	-- Si le dernier caractère n'est pas une parenthèse
    	IF RIGHT(@sql_recreate_table, CHARINDEX(')', REVERSE(@sql_recreate_table)) - 1) = ''
    	BEGIN
    		SET @sql_recreate_table = @sql_recreate_table + ' ON Test'
     
    		BEGIN TRY
    			BEGIN TRANSACTION
    				EXEC (@sql_drop_table)
    				EXEC (@sql_recreate_table)
    			COMMIT TRANSACTION
    		END TRY
    		BEGIN CATCH
    			DECLARE @err_msg nvarchar(4000) = 'Line ' + CAST(ERROR_LINE() AS varchar(10)) + ' - ' + ERROR_MESSAGE()
    				, @err_svt int = ERROR_SEVERITY()
    				, @err_stt int = ERROR_STATE()
     
    			IF XACT_STATE() <> 0
    			BEGIN
    				ROLLBACK TRANSACTION;
    			END
     
    			RAISERROR(@err_msg, @err_svt, @err_stt);
    		END CATCH
    	END
    END
    @++

  7. #7
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut
    Salut, merci pour ta query ça m'aide !

    J'ai réfléchi un peu et ai pensé à ceci comme solution:


    J’ai créé un role : role_allowed_to_create_table
    J’ai créé un schema : BUSINESS_LOAD
    J’ai créé un filegroup : BUSINESS_DATA (disque séparé)

    Ce role role_allowed_to_create_table peut faire (alter/insert/delete/update) sur le schema BUSINESS_LOAD
    J’ai rajouté aussi un GRANT CREATE TABLE pour le role role_allowed_to_create_table sur la database

    Ensuite je crée le Trigger suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    CREATE TRIGGER TR_CREATE_TABLE_FG
    	ON DATABASE
    	FOR CREATE_TABLE
    AS
    BEGIN
    	/*variables declaration*/
    		DECLARE @x xml = EVENTDATA();
    		DECLARE @sql_create_table nvarchar(max);
    		DECLARE @login VARCHAR(255);
    		DECLARE @user VARCHAR(255);
    		DECLARE @role VARCHAR(255);
    	/*GET login from session_id*/
    		SELECT @login = login_name 
    		FROM sys.dm_exec_sessions 
    		WHERE session_id = @@SPID;
    	/*GET user FROM login*/
    		SELECT @user = d.name
    		FROM sys.database_principals AS d
    		INNER JOIN sys.server_principals AS s
    		ON d.sid = s.sid
    		WHERE s.name = @login;
    	/*GET role FROM user*/
    		SELECT @role = r.name
    		FROM sys.database_role_members AS m
    		INNER JOIN sys.database_principals AS r
    		ON m.role_principal_id = r.principal_id
    		INNER JOIN sys.database_principals AS u
    		ON u.principal_id = m.member_principal_id
    		WHERE u.name = @user;
     
    	/*If CREATE TABLE statement executed by role_allowed_to_create_table*/
    	IF(@role IS NOT NULL AND @role ='role_allowed_to_create_table')
    		BEGIN
    			/*GET statement*/
    			SELECT @sql_create_table = N.n.value('(./TSQLCommand/CommandText)[1]', 'varchar(max)') FROM @x.nodes('/EVENT_INSTANCE') AS N(n)
    			/*If statement does not contains ON[BUSINESS_DATA] string*/
    			IF (@sql_create_table IS NOT NULL AND @sql_create_table NOT LIKE '%ON%[BUSINESS_DATA]%')
    			BEGIN
    				PRINT 'ERROR : You must specify the good file_group !!! ==> Please add ON[BUSINESS_DATA] at the end of create table statement'
    				ROLLBACK TRANSACTION;
    			END
    		END
    END
    Je suis conscient du fait que faire un LIKE '%ON%[BUSINESS_DATA]%' n'est pas très clean, mais ça devrait fonctionner d'après vous?
    -Les users qui ne sont pas dans ce role ne rentreraient pas dans le IF et donc peuvent faire ce qu'ils veulent ( à condition de pouvoir créer une table)

  8. #8
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Bonjour,

    Pour récupérer le nom de l'utilisateur de la session courante, vous pouvez utiliser SUSER_NAME().
    Identiquement, vous pouvez récupérer le login à l'aide de ORIGINAL_LOGIN(); cependant le code affecte la variable, mais celle-ci n'est pas utilisée ensuite : c'est normal puisque pour ce que vous voulez réaliser, ce n'est pas nécessaire.
    Enfin, pour vérifier si un principal est membre d'un rôle particulier, vous pouvez utiliser la fonction IS_ROLEMEMBER()

    Le code lit ensuite :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT @sql_create_table = N.n.value('(./TSQLCommand/CommandText)[1]', 'varchar(max)') FROM @x.nodes('/EVENT_INSTANCE') AS N(n)
    IF (@sql_create_table IS NOT NULL
    @sql_create_table ne sera jamais à NULL puisque le trigger ne peut se déclencher que sur un évènement de création de table; ou alors, l'avez-vous combiné à un autre évènement ?

    Vous devriez remplacer le PRINT par un RAISERROR ou THROW.
    Le ROLLBACK est bon, mais il faudriat avant cela vérifier qu'il y a bien une transaction restée ouverte : cela se fait à l'aide de la fonction XACT_STATE()

    @++

  9. #9
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut
    Merci pour l'aide , le trigger adapté suite à tes remarques:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    ALTER TRIGGER TR_CREATE_TABLE_FG
    	ON DATABASE
    	FOR CREATE_TABLE
    AS
    BEGIN
    	/*variables declaration*/
    		DECLARE @x xml = EVENTDATA();
    		DECLARE @sql_create_table nvarchar(max);
    	/*IF the user is a member of specified role, test if table is created in authorized FG, if it not ==> Rollback transaction*/
    		IF(IS_ROLEMEMBER('role_allowed_to_create_table',SUSER_NAME()) = 1)
    		BEGIN
    			/*GET statement*/
    			SELECT @sql_create_table = N.n.value('(./TSQLCommand/CommandText)[1]', 'varchar(max)') FROM @x.nodes('/EVENT_INSTANCE') AS N(n)
    			/*If statement does not contains ON[BUSINESS_DATA] string*/
    			IF (@sql_create_table NOT LIKE '%ON%[BUSINESS_DATA]%')
    			BEGIN
    				DECLARE @err_msg nvarchar(4000) = 'ERROR : You must specify the good file_group !!! ==> Please add ON[BUSINESS_DATA] at the end of create table statement'
    				DECLARE @err_svt int = ERROR_SEVERITY()
    				DECLARE @err_stt int = ERROR_STATE()
    				RAISERROR(@err_msg, @err_svt, @err_stt);
    				IF XACT_STATE() <> 0
    				BEGIN
    					ROLLBACK TRANSACTION;
    				END
    			END
    		END
    END
    J'ai testé ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    /* case 1 : db_owner*/
    	CREATE TABLE dbo.test
    	(
    		id int
    	);
    	--  ==> OK j'ai su créer
    	DROP TABLE dbo.test;
     
    /* switch to user to test*/
    	EXECUTE AS LOGIN = 'VOO\le_user_a_tester';
    /* case 2 : wrong schema*/
    	CREATE TABLE dbo.test
    	(
    		id int
    	);
    	--  ==> OK je n'ai pas su créer car ne peux pas créer dans ce schema
    /* case 3 : good schema but no FG specified*/
    	CREATE TABLE business_load.test
    	(
    		id int
    	);
    		/*Result*/
    		--ERROR : You must specify the good file_group !!! ==> Please add ON[BUSINESS_DATA] at the end of create table statement
    		--Msg 3609, Level 16, State 2, Line 1
    		--The transaction ended in the trigger. The batch has been aborted.
     
    	--  ==> OK je n'ai pas su créer car ne peux pas créer dans ce schema si je ne spécifie pas le bon filegroup
    /* case 4 : good schema and good FG specified*/
    	CREATE TABLE business_load.test
    	(
    		id int
    	)ON [BUSINESS_DATA];
    	--  ==> OK j'ai su créer
    	DROP TABLE business_load.test
    Tout à l'air OK !

  10. #10
    Modérateur

    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Janvier 2005
    Messages
    5 826
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Janvier 2005
    Messages : 5 826
    Points : 12 371
    Points
    12 371
    Par défaut
    Impeccable. Une dernière petite suggestion : Dès SQL Server 2005, on peut cumuler les déclarations (sans leur affecation) en un seul DECLARE :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    DECLARE @err_msg nvarchar(4000)
    	, @err_svt int
    	, @err_stt int
     
    SELECT	@err_msg = 'ERROR : You must specify the good file_group !!! ==> Please add ON[BUSINESS_DATA] at the end of create table statement'
    	, @err_svt = ERROR_SEVERITY()
    	, @err_stt = ERROR_STATE()
    Et dès SQL Server 2008, on peut écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    DECLARE @err_msg nvarchar(4000) = 'ERROR : You must specify the good file_group !!! ==> Please add ON[BUSINESS_DATA] at the end of create table statement'
    	, @err_svt int = ERROR_SEVERITY()
    	, @err_stt int = ERROR_STATE()
    @++

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut
    Je suis de retour .

    Un des users a réussi à créer une table via un SELECT INTO.
    Par contre ça ne fonctionne pas systématiquement. Ca semble dépendre du schema de la table source....


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT TOP 10 * 
    	INTO BUSINESS_LOAD.test
    	FROM dbo.DimDate
    OK : ne peut pas créer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT TOP 10 * 
    	INTO BUSINESS_LOAD.test
    	FROM staging.ma_table
    NOT OK : a réussi à créer




    Une idée?

  12. #12
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    Citation Envoyé par vinch999 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	FROM staging.ma_table
    staging.ma_table... est-ce réellement le VRAI nom de la table avec laquelle ça passe ???

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut
    Non,

    peu importe le nom de la table. C'est le niveau schema qui pose problème

  14. #14
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 565
    Points
    52 565
    Billets dans le blog
    5
    Par défaut
    Essayez ceci et dites moi ce que vous en pensez... si ça marche je vais le publier...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    CREATE TRIGGER E_CREATE_TABLE
    ON DATABASE
    FOR CREATE_TABLE
    AS
    SET NOCOUNT ON;
     
    IF NOT (IS_ROLEMEMBER('role_allowed_to_create_table', USER) = 1)
       RETURN;
     
    DECLARE @DDL_DATA XML = EVENTDATA(), 
            @SCH sysname, 
    		@TBL sysname,
    		@SQL NVARCHAR(max), 
    		@FG sysname,
    		@ISFG bit,
    		@IDX INT,
    		@OID INT;
     
    SELECT @SCH = @DDL_DATA.value('(EVENT_INSTANCE/SchemaName)[1]', 'sysname'),
           @TBL = @DDL_DATA.value('(EVENT_INSTANCE/ObjectName)[1]', 'sysname');
     
    SELECT  @FG = fg.name, @IDX = i.index_id, @OID = i.object_id,
            @ISFG = CASE partition_number WHEN 1 THEN 1 ELSE 0 END 
    FROM   sys.indexes AS i
           JOIN sys.objects AS o
    	        ON i.object_id = o.object_id
    	   JOIN sys.schemas AS s
    	        ON o.schema_id = s.schema_id
           JOIN sys.partitions p 
                ON p.object_id = i.object_id 
                AND p.index_id = i.index_id 
           JOIN sys.allocation_units a 
                ON a.container_id = p.partition_id
           JOIN sys.filegroups AS fg 
    	        ON a.data_space_id = fg.data_space_id
    WHERE  i.index_id IN (0, 1)
      AND  o.name = @TBL
      AND  s.name = @SCH;
     
    IF @FG = 'MonFileGroup'
       RETURN
     
    IF @ISFG = 0
    BEGIN
       RAISERROR('la table %s.%s ne peut pas être créée sur une partition. Elle va être détruite.', 16, 1, @SCH, @TBL);
       RETURN;
    END
    ELSE 	 
       RAISERROR('la table %s.%s ne peut pas être créée sur le groupe de fichier %s. Elle va être migré sur le groupe de fichiers adéquat.', 16, 1, @SCH, @TBL, @FG);
    ROLLBACK;
     
    IF @IDX = 0
    BEGIN
    -- pas d'index cluer ton déplace la table en en créant un puis en le supprimant
       SET @SQL = 'ALTER TABLE [' + @SCH + '].[' + @TBL + '] ADD _UID UNIQUEIDENTIFIER DEFAULT NEWID() CONSTRAINT _PK PRIMARY KEY ON MonFileGroup';
       EXEC (@SQL);
       SET @SQL = 'ALTER TABLE [' + @SCH + '].[' + @TBL + '] DROP CONSTRAINT _PK, COLUMN _UID';
       EXEC (@SQL);
    END
    ELSE
    BEGIN
    -- index cluster on le reconstruit à l'identique sur le filegroup de destination
    	WITH  
    	idc AS (SELECT ic.object_id, index_id,  
    				   ROW_NUMBER() OVER(PARTITION BY ic.object_id, index_id, is_included_column
    									 ORDER BY index_column_id) AS index_column_id,
    				   is_included_column,  
    				   c.name, CASE WHEN is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END AS ord
    			FROM   sys.index_columns AS ic
    				   INNER JOIN sys.columns AS c
    						 ON ic.object_id = c.object_id
    							AND ic.column_id = c.column_id
    			WHERE  ic.index_id = 1
    			  AND  ic.object_id = @OID
    	),
    	idk AS (SELECT object_id, index_id,  index_column_id, 1 AS cols,
    				   CAST('[' + name + '] ' + ord AS NVARCHAR(MAX)) AS KEY_DEF
    			FROM   idc        
    			WHERE  is_included_column = 0
    			  AND  index_column_id = 1
    			UNION ALL
    			SELECT idc.object_id, idc.index_id, idc.index_column_id, cols + 1,
    				   KEY_DEF + ', ' + '[' + idc.name + '] ' + ord
    			FROM   idc
    				   INNER JOIN idk
    						 ON idc.object_id = idk.object_id AND
    						 idc.index_id = idk.index_id AND
    						 idc.index_column_id = idk.index_column_id + 1
    			WHERE  idc.is_included_column = 0),
    	dfi AS (SELECT idk.*,  
    				   ROW_NUMBER() OVER(PARTITION BY idk.object_id, idk.index_id  
    									 ORDER BY cols DESC) AS N
    			FROM   idk
    	)
    	SELECT @SQL = 'CREATE '
    		   + CASE WHEN is_unique = 1 THEN ' UNIQUE ' ELSE '' END
    		   + ' CLUSTERED '+
    		   ' INDEX [' + i.name + '] ON [' + s.name +'].[' + o.name
    		   +'] (' + KEY_DEF +')' + ' WITH (DROP_EXISTING = ON) ON MonFileGroup;' 
    	FROM   dfi
    		   INNER JOIN sys.indexes AS i
    				 ON dfi.object_id = i.object_id
    					AND dfi.index_id = i.index_id
    		   INNER JOIN sys.objects AS o
    				 ON i.object_id = o.object_id
    		   INNER JOIN sys.schemas AS s
    				 ON o.schema_id = s.schema_id
    	WHERE  o."type" = 'U' AND N = 1;
    	EXEC (@SQL);
    END;
     
    GO
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  15. #15
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Citation Envoyé par vinch999 Voir le message
    Non,

    peu importe le nom de la table.
    si, c'est bien le nom de la table qui pose problème

    Tel que vous avez écrit votre like, il suffit que la commande contient "ON" puis contiennent au moins une lettre parmi celles-ci : B-U-S-I-N-E-S-S-_-D-A-T-A.

    il faudrait a minima spécifier le caractère d’échappement pour votre clause LIKE.

    Par exemple, même sur votre schéma dbo, ceci devrait passer :

    SELECT TOP 10 *
    INTO BUSINESS_LOAD.test
    FROM dbo.One_Table

  16. #16
    Membre régulier
    Profil pro
    Inscrit en
    Mai 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2009
    Messages : 212
    Points : 71
    Points
    71
    Par défaut
    Effectivement , bien vu aieeeuuuuu !

    J'ai mis plutôt ceci : NOT LIKE '%ON%\[BUSINESS_DATA\]%' ESCAPE '\'

    ça fonctionne


    @SQLpro : je vais tester ça merci !

  17. #17
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 565
    Points
    52 565
    Billets dans le blog
    5
    Par défaut
    Vous faites tous fausse route... Utiliser un LIKE dans une chaine de caractère de commande SQL est le plus sur moyen qu'un jour ça merde grave. C'est une imbécilité !
    Il faut travailler au niveau logique :
    1) laisser la table se créer au mauvais endroit et identifier logquement que c'est au mauvais endroit
    2) si c'est au mauvais endroit, déplacer logiquement la table d'un groupe de fichier à l'autre à l'aide de ALTER INDEX ... DROP_EXISTING .... ON MON_FILE_GROUP;

    C'est ce que propose mon script !

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

Discussions similaires

  1. [2008R2] création de table pour des données spécifiques
    Par Kagami dans le forum Développement
    Réponses: 3
    Dernier message: 21/01/2014, 17h16
  2. [AC-2003] création de table sur base sql distante
    Par novice06 dans le forum VBA Access
    Réponses: 3
    Dernier message: 21/06/2010, 11h27
  3. Requête création de table sur base mise en réseau
    Par boss dans le forum Requêtes et SQL.
    Réponses: 3
    Dernier message: 24/01/2007, 15h49
  4. création d'enregistrement sur 2 tables liées
    Par cyrillescot dans le forum Access
    Réponses: 2
    Dernier message: 15/01/2007, 08h22
  5. forcer la création de tables InnoDB sur Free
    Par Eldarion dans le forum SQL Procédural
    Réponses: 2
    Dernier message: 13/10/2005, 22h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo