web-dev-qa-db-fra.com

T-SQL Comment créer des tables de manière dynamique dans des procédures stockées?

Code comme ça, mais c'est faux:

CREATE PROC sp_createATable
  @name        VARCHAR(10),
  @properties  VARCHAR(500)
AS
  CREATE TABLE @name
  (
    id  CHAR(10)  PRIMARY KEY,
    --...Properties extracted from @properties
  );

Pourriez-vous me dire comment y faire face? Cela me trouble vraiment.

16
tmj

Vous utilisez une variable de table, c’est-à-dire que vous devez déclarer la table. Ce n'est pas une table temporaire.

Vous créez une table temporaire comme ceci:

CREATE TABLE #customer
(
     Name varchar(32) not null
)

Vous déclarez une variable de table comme ceci:

DECLARE @Customer TABLE
(
      Name varchar(32) not null
)

Notez qu'une table temporaire est déclarée à l'aide de # et qu'une variable de table est déclarée à l'aide de @. Allez lire sur la différence entre les variables de table et les tables temporaires.

PDATE:

En fonction de votre commentaire ci-dessous, vous essayez réellement de créer des tables dans une procédure stockée. Pour cela, vous devez utiliser du SQL dynamique. Fondamentalement, le SQL dynamique vous permet de construire une instruction SQL sous la forme d'une chaîne, puis de l'exécuter. C’est le SEUL moyen de créer une table dans une procédure stockée. Je vais vous montrer comment et ensuite expliquer pourquoi ce n'est généralement pas une bonne idée.

Maintenant, pour un exemple simple (je n’ai pas testé ce code mais il devrait vous donner une bonne indication sur la façon de le faire):

CREATE PROCEDURE sproc_BuildTable 
    @TableName NVARCHAR(128)
   ,@Column1Name NVARCHAR(32)
   ,@Column1DataType NVARCHAR(32)
   ,@Column1Nullable NVARCHAR(32)
AS

   DECLARE @SQLString NVARCHAR(MAX)
   SET @SQString = 'CREATE TABLE '+@TableName + '( '+@Column1Name+' '+@Column1DataType +' '+@Column1Nullable +') ON PRIMARY '

   EXEC (@SQLString)
   GO

Cette procédure stockée peut être exécutée comme ceci:

sproc_BuildTable 'Customers','CustomerName','VARCHAR(32)','NOT NULL'

Ce type de procédure stockée présente des problèmes majeurs.

Il sera difficile de prendre en charge des tables complexes. Imaginez la structure de table suivante:

CREATE TABLE [dbo].[Customers] (
    [CustomerID] [int] IDENTITY(1,1) NOT NULL,
    [CustomerName] [nvarchar](64) NOT NULL,
    [CustomerSUrname] [nvarchar](64) NOT NULL,
    [CustomerDateOfBirth] [datetime] NOT NULL,
    [CustomerApprovedDiscount] [decimal](3, 2) NOT NULL,
    [CustomerActive] [bit] NOT NULL,
    CONSTRAINT [PK_Customers] PRIMARY KEY CLUSTERED 
    (
        [CustomerID] ASC
    ) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,      ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

ALTER TABLE [dbo].[Customers] ADD CONSTRAINT [DF_Customers_CustomerApprovedDiscount] DEFAULT ((0.00)) FOR [CustomerApprovedDiscount]
GO 

Ce tableau est un peu plus complexe que le premier exemple, mais pas beaucoup. La procédure stockée sera beaucoup, beaucoup plus complexe à gérer. Ainsi, bien que cette approche puisse fonctionner pour de petites tables, elle sera rapidement ingérable.

La création de tables nécessite une planification. Lorsque vous créez des tables, elles doivent être placées de manière stratégique sur différents groupes de fichiers. Cela garantit que vous ne causez pas de conflit d'E/S de disque. Comment allez-vous gérer l'évolutivité si tout est créé sur le groupe de fichiers principal?

Pouvez-vous préciser pourquoi vous avez besoin de créer des tables de manière dynamique?

PDATE 2:

Mise à jour retardée en raison de la charge de travail. J'ai lu votre commentaire sur la nécessité de créer un tableau pour chaque magasin et je pense que vous devriez le faire comme dans l'exemple que je vais vous donner.

Dans cet exemple, je pose les hypothèses suivantes:

  1. C'est un site de commerce électronique qui compte de nombreux magasins
  2. Un magasin peut avoir de nombreux articles à vendre.
  3. Un article particulier (bon) peut être vendu dans de nombreux magasins
  4. Un magasin facturera des prix différents pour différents articles (marchandises)
  5. Tous les prix sont en $ (USD)

Supposons que ce site de commerce électronique vend des consoles de jeux (c.-à-d. Wii, PS3, XBOX360).

En regardant mes hypothèses, je vois une relation classique plusieurs à plusieurs. Un magasin peut vendre de nombreux articles (biens) et des articles (biens) peuvent être vendus dans de nombreux magasins. Divisons cela en tables.

J'aurais d'abord besoin d'une table de magasin pour stocker toutes les informations sur le magasin.

Une simple table de magasin pourrait ressembler à ceci:

CREATE TABLE [dbo].[Shop](
    [ShopID] [int] IDENTITY(1,1) NOT NULL,
    [ShopName] [nvarchar](128) NOT NULL,
    CONSTRAINT [PK_Shop] PRIMARY KEY CLUSTERED 
    (
      [ShopID] ASC
    ) WITH (
              PAD_INDEX  = OFF
              , STATISTICS_NORECOMPUTE  = OFF
              , IGNORE_DUP_KEY = OFF
              , ALLOW_ROW_LOCKS  = ON
              , ALLOW_PAGE_LOCKS  = ON
    ) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

Insérons trois magasins dans la base de données à utiliser lors de notre exemple. Le code suivant insérera trois magasins:

INSERT INTO Shop
SELECT 'American Games R US'
UNION
SELECT 'Europe Gaming Experience'
UNION
SELECT 'Asian Games Emporium'

Si vous exécutez un SELECT * FROM Shop, vous verrez probablement ce qui suit:

ShopID  ShopName
1           American Games R US
2           Asian Games Emporium
3           Europe Gaming Experience

Bon, passons maintenant à la table Items (goods). Puisque les articles/biens sont des produits de diverses sociétés, je vais appeler le produit de table. Vous pouvez exécuter le code suivant pour créer une table Product simple.

CREATE TABLE [dbo].[Product](
    [ProductID] [int] IDENTITY(1,1) NOT NULL,
    [ProductDescription] [nvarchar](128) NOT NULL,
 CONSTRAINT [PK_Product] PRIMARY KEY CLUSTERED 
 (
     [ProductID] ASC
 )WITH (PAD_INDEX  = OFF
        , STATISTICS_NORECOMPUTE  = OFF
        , IGNORE_DUP_KEY = OFF
        ,     ALLOW_ROW_LOCKS  = ON
         , ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  ) ON [PRIMARY]

GO

Remplissons la table des produits avec certains produits. Exécutez le code suivant pour insérer certains produits:

INSERT INTO Product
SELECT 'Wii'
UNION 
SELECT 'PS3'
UNION 
SELECT 'XBOX360'

Si vous exécutez SELECT * FROM Product, vous verrez probablement ce qui suit:

ProductID   ProductDescription
1           PS3
2           Wii
3           XBOX360

OK, à ce stade, vous avez les informations sur le produit et le magasin. Alors, comment les réunissez-vous? Nous savons bien que nous pouvons identifier le magasin par sa colonne de clé primaire ShopID et que nous pouvons identifier un produit par sa colonne de clé primaire ProductID. De plus, comme chaque magasin a un prix différent pour chaque produit, nous devons enregistrer le prix que le magasin facture pour le produit.

Nous avons donc un tableau qui associe la boutique au produit. Nous appellerons cette table ShopProduct. Une version simple de ce tableau pourrait ressembler à ceci:

CREATE TABLE [dbo].[ShopProduct](
[ShopID] [int] NOT NULL,
[ProductID] [int] NOT NULL,
[Price] [money] NOT NULL,
CONSTRAINT [PK_ShopProduct] PRIMARY KEY CLUSTERED 
 (
     [ShopID] ASC,
      [ProductID] ASC
 )WITH (PAD_INDEX  = OFF,
     STATISTICS_NORECOMPUTE  = OFF, 
     IGNORE_DUP_KEY = OFF, 
     ALLOW_ROW_LOCKS  = ON,
     ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  ) ON [PRIMARY]

 GO

Supposons donc que le magasin American Games R Us ne vend que des consoles américaines, que Europe Gaming Experience vend toutes les consoles et que Asian Games Emporium ne vend que des consoles asiatiques. Nous aurions besoin de mapper les clés primaires des tables Shop et Product dans la table ShopProduct.

Voici comment nous allons faire la cartographie. Dans mon exemple, l'American Games R Us a une valeur ShopID de 1 (il s'agit de la valeur de clé primaire) et je peux voir que le XBOX360 a une valeur de 3 et que la boutique a proposé le XBOX360 à 159,99 $

En exécutant le code suivant, vous compléterez le mappage:

INSERT INTO ShopProduct VALUES(1,3,159.99)

Nous souhaitons maintenant ajouter tous les produits à la boutique Europe Gaming Experience. Dans cet exemple, nous savons que le magasin Europe Gaming Experience a un ShopID de 3 et, puisqu'il vend toutes les consoles, nous aurons besoin d'insérer le ProductID 1, 2 et 3 dans le tableau de mappage. Supposons que les prix des consoles (produits) dans la boutique Europe Gaming Experience sont les suivants: 1- La PS3 se vend 259,99 $, 2- La Wii se vend 159,99 $, 3- Le XBOX360 se vend 199,99 $.

Pour que ce mappage soit terminé, vous devez exécuter le code suivant:

INSERT INTO ShopProduct VALUES(3,2,159.99) --This will insert the WII console into the mapping table for the Europe Gaming Experience Shop with a price of 159.99
INSERT INTO ShopProduct VALUES(3,1,259.99) --This will insert the PS3 console into the mapping table for the Europe Gaming Experience Shop with a price of 259.99
INSERT INTO ShopProduct VALUES(3,3,199.99) --This will insert the XBOX360 console into the mapping table for the Europe Gaming Experience Shop with a price of 199.99

À ce stade, vous avez mappé deux magasins et leurs produits dans le tableau de mappage. OK, alors maintenant, comment puis-je réunir tout cela pour montrer à un utilisateur qui navigue sur le site? Supposons que vous souhaitiez afficher tous les produits de European Gaming Experience à un utilisateur sur une page Web. Vous devez exécuter la requête suivante:

SELECT      Shop.*
        , ShopProduct.*
        , Product.*
FROM         Shop 
INNER JOIN  ShopProduct ON Shop.ShopID = ShopProduct.ShopID 
INNER JOIN  Product ON ShopProduct.ProductID = Product.ProductID
WHERE       Shop.ShopID=3

Vous verrez probablement les résultats suivants:

ShopID     ShopName                 ShopID  ProductID   Price   ProductID   ProductDescription
3          Europe Gaming Experience   3         1       259.99  1           PS3
3          Europe Gaming Experience   3         2       159.99  2           Wii
3          Europe Gaming Experience   3         3       199.99  3           XBOX360

Maintenant, pour un dernier exemple, supposons que votre site Web possède une fonctionnalité qui recherche le prix le moins cher pour une console. Un utilisateur demande de trouver les prix les moins chers pour XBOX360.

Vous pouvez exécuter la requête suivante:

 SELECT     Shop.*
        , ShopProduct.*
        , Product.*
 FROM         Shop 
 INNER JOIN  ShopProduct ON Shop.ShopID = ShopProduct.ShopID 
 INNER JOIN  Product ON ShopProduct.ProductID = Product.ProductID
 WHERE      Product.ProductID =3  -- You can also use Product.ProductDescription = 'XBOX360'
 ORDER BY    Price ASC

Cette requête renvoie une liste de tous les magasins vendant en premier la XBOX360 avec le magasin le moins cher, etc.

Vous remarquerez que je n'ai pas ajouté la boutique des jeux asiatiques. En guise d’exercice, ajoutez la boutique de jeux asiatiques au tableau de correspondance avec les produits suivants: l’Asian Games Emporium vend la console de jeux Wii à 99,99 $ et la console PS3 à 159,99 $. Si vous travaillez à travers cet exemple, vous devez maintenant comprendre comment modéliser une relation plusieurs à plusieurs.

J'espère que cela vous aidera dans vos déplacements avec la conception de bases de données.

40
Namphibian

Vous devrez créer cette instruction CREATE TABLE à partir des entrées, puis l'exécuter.

Un exemple simple:

declare @cmd nvarchar(1000), @TableName nvarchar(100);

set @TableName = 'NewTable';

set @cmd = 'CREATE TABLE dbo.' + quotename(@TableName, '[') + '(newCol int not null);';

print @cmd;

--exec(@cmd);
2
Nathan Skerl

Tout d'abord, vous semblez mélanger des variables de tableau et des tableaux.

De toute façon, vous ne pouvez pas passer le nom de la table comme ça. Pour cela, vous devrez utiliser TSQL dynamique.

Si vous voulez simplement déclarer une variable de table:

CREATE PROC sp_createATable 
  @name        VARCHAR(10), 
  @properties  VARCHAR(500) 
AS 
  declare @tablename TABLE
  ( 
    id  CHAR(10)  PRIMARY KEY 
  ); 

Le fait que vous souhaitiez créer une procédure stockée pour créer dynamiquement des tables peut laisser penser que votre conception est erronée.

2
Mitch Wheat

C'est un moyen de créer des tables de manière dynamique à l'aide de procédures stockées T-SQL:

declare @cmd nvarchar(1000), @MyTableName nvarchar(100);
set @MyTableName = 'CustomerDetails';
set @cmd = 'CREATE TABLE dbo.' + quotename(@MyTableName, '[') + '(ColumnName1 int not null,ColumnName2 int not null);';

Exécutez-le comme:

exec(@cmd);
1
user6341745

Vous pouvez écrire le code ci-dessous: -

create procedure spCreateTable
   as
    begin
       create table testtb(Name varchar(20))
    end

l'exécuter comme: -

exec spCreateTable

0
Henry Disoza