sql >> データベース >  >> RDS >> Sqlserver

T-SQLストアドプロシージャで動的にテーブルを作成する方法は?

    テーブル変数を使用しています。つまり、テーブルを宣言する必要があります。これは一時的なテーブルではありません。

    次のように一時テーブルを作成します:

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

    次のようにテーブル変数を宣言します:

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

    一時テーブルは#を使用して宣言され、テーブル変数は@を使用して宣言されていることに注意してください。テーブル変数と一時テーブルの違いについて読んでください。

    更新:

    以下のコメントに基づいて、実際にはストアドプロシージャでテーブルを作成しようとしています。このためには、動的SQLを使用する必要があります。基本的に動的SQLを使用すると、文字列の形式でSQLステートメントを作成し、それを実行できます。これは、ストアドプロシージャでテーブルを作成できる唯一の方法です。その方法を説明してから、これが一般的に適切でない理由について説明します。

    ここで簡単な例を示します(このコードはテストしていませんが、その方法がわかります):

    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 '[email protected] + '( '[email protected]+' '[email protected] +' '[email protected] +') ON PRIMARY '
    
       EXEC (@SQLString)
       GO
    

    このストアドプロシージャは、次のように実行できます。

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

    このタイプのストアドプロシージャにはいくつかの大きな問題があります。

    複雑なテーブルに対応するのは難しいでしょう。次のテーブル構造を想像してみてください。

    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 
    

    このテーブルは最初の例よりも少し複雑ですが、それほど多くはありません。ストアドプロシージャは、処理がはるかに複雑になります。したがって、このアプローチは小さなテーブルでは機能する可能性がありますが、すぐに管理できなくなります。

    テーブルの作成には計画が必要です。テーブルを作成するときは、それらを異なるファイルグループに戦略的に配置する必要があります。これは、ディスクI/Oの競合を引き起こさないようにするためです。すべてがプライマリファイルグループで作成されている場合、スケーラビリティにどのように対処しますか?

    テーブルを動的に作成する必要がある理由を明確にできますか?

    更新2:

    ワークロードが原因で更新が遅れた。ショップごとにテーブルを作成する必要があるというコメントを読みました。これから説明する例のように、テーブルを作成することを検討する必要があると思います。

    この例では、次のことを前提としています。

    1. 多くのショップがあるeコマースサイトです
    2. ショップには多くの商品(商品)を販売できます。
    3. 特定の商品(商品)は多くのショップで販売できます
    4. ショップは商品(商品)ごとに異なる価格を請求します
    5. すべての価格は$(USD)です

    このeコマースサイトがゲーム機(Wii、PS3、XBOX360など)を販売しているとします。

    私の仮定を見ると、古典的な多対多の関係がわかります。ショップは多くの商品(商品)を販売でき、商品(商品)は多くの店舗で販売できます。これを表に分けてみましょう。

    まず、ショップに関するすべての情報を保存するためのショップテーブルが必要です。

    単純なショップテーブルは次のようになります:

    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
    

    この例で使用する3つのショップをデータベースに挿入してみましょう。次のコードは3つのショップを挿入します:

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

    SELECT * FROM Shopを実行した場合 おそらく次のように表示されます:

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

    では、アイテム(商品)テーブルに移動しましょう。商品・商品は様々な会社の商品ですので、テーブル商品と呼びます。次のコードを実行して、簡単なProductテーブルを作成できます。

    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
    

    productsテーブルにいくつかの製品を入力してみましょう。次のコードを実行して、いくつかの製品を挿入します。

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

    SELECT * FROM Productを実行した場合 おそらく次のように表示されます:

    ProductID   ProductDescription
    1           PS3
    2           Wii
    3           XBOX360
    

    OK、この時点で、商品とショップの両方の情報があります。では、どのようにそれらをまとめますか? ShopIDの主キー列でショップを識別でき、ProductIDの主キー列で製品を識別できることはわかっています。また、ショップごとに商品ごとに価格が異なるため、ショップが商品に対して請求する価格を保存する必要があります。

    したがって、ショップを製品にマップするテーブルがあります。このテーブルをShopProductと呼びます。このテーブルの単純なバージョンは次のようになります。

    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
    

    したがって、American Games R Usショップはアメリカのコンソールのみを販売し、Europe Gaming Experienceはすべてのコンソールを販売し、AsianGamesEmporiumはアジアのコンソールのみを販売するとします。ショップテーブルと商品テーブルの主キーをShopProductテーブルにマッピングする必要があります。

    これがマッピングの方法です。私の例では、American Games R UsのShopID値は1(これは主キー値です)であり、XBOX360の値は3であり、ショップはXBOX360を159.99ドルでリストしています

    次のコードを実行すると、マッピングが完了します。

    INSERT INTO ShopProduct VALUES(1,3,159.99)
    

    次に、すべての製品をEuropeGamingExperienceショップに追加します。この例では、Europe Gaming ExperienceショップのShopIDが3であり、すべてのコンソールを販売しているため、ProductID 1、2、および3をマッピングテーブルに挿入する必要があります。 Europe Gaming Experienceショップのコンソール(製品)の価格が次のとおりであると仮定します。1-PS3は259.99ドル、2-Wiiは159.99ドル、3-XBOX360は199.99ドルで販売されています。

    このマッピングを行うには、次のコードを実行する必要があります。

    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
    

    この時点で、2つのショップとその製品をマッピングテーブルにマッピングしました。では、これをすべてまとめて、ユーザーがWebサイトを閲覧していることを示すにはどうすればよいでしょうか。 European Gaming Experienceのすべての製品をWebページのユーザーに表示したいとします。次のクエリを実行する必要があります:

    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
    

    おそらく次の結果が表示されます:

    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
    

    最後の例として、Webサイトにコンソールの最も安い価格を見つける機能があると仮定しましょう。ユーザーがXBOX360の最も安い価格を探すように求めています。

    次のクエリを実行できます:

     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
    

    このクエリは、XBOX360を最も安いショップで最初に販売しているすべてのショップのリストを返します。

    私がアジア競技大会ショップを追加していないことに気付くでしょう。演習として、次の製品を使用してアジア競技大会ショップをマッピングテーブルに追加します。アジア競技大会エンポリアムはWiiゲームコンソールを99.99ドルで、PS3コンソールを159.99ドルで販売しています。この例を実行すると、多対多の関係をモデル化する方法を理解できるはずです。

    これがデータベース設計での旅行に役立つことを願っています。



    1. postgresqlinformation_schemaのすべてのテーブルを一覧表示します

    2. 簡単な全文検索をお探しですか? MySQL InnoDB+CakePHPとWordStemmingをお試しください

    3. AndroidでSqLiteデータベースをリセットする方法は?

    4. 列にNULLが含まれるレコードを検索する方法