21

像这样的代码,但它是错误的:

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

你能告诉我如何处理它吗?这真的让我很困扰。

4

5 回答 5

50

您正在使用表变量,即您应该声明该表。这不是临时表。

您可以像这样创建一个临时表:

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 '+@TableName + '( '+@Column1Name+' '+@Column1DataType +' '+@Column1Nullable +') 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. 这是一个拥有许多商店的电子商务网站
  2. 一家商店可以有许多物品(商品)要出售。
  3. 可以在许多商店出售特定商品(商品)
  4. 一家商店会针对不同的商品(商品)收取不同的价格
  5. 所有价格均以美元 (USD) 为单位

假设这个电子商务网站销售游戏机(即 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

让我们在数据库中插入三个商店以在我们的示例中使用。以下代码将插入三个商店:

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

如果您执行 a SELECT * FROM Shop您可能会看到以下内容:

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

好的,现在让我们转到 Items(商品)表。由于物品/商品是各种公司的产品,我将其称为表产品。您可以执行以下代码来创建一个简单的 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

让我们用一些产品填充产品表。执行以下代码插入一些产品:

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

如果执行SELECT * FROM Product,您可能会看到以下内容:

ProductID   ProductDescription
1           PS3
2           Wii
3           XBOX360

好的,此时您拥有产品和商店信息。那么如何将它们组合在一起呢?好吧,我们知道我们可以通过 ShopID 主键列来识别商店,并且我们知道我们可以通过 ProductID 主键列来识别产品。此外,由于每个商店对每种产品都有不同的价格,我们需要存储商店对产品收取的价格。

因此,我们有一个将 Shop 映射到产品的表。我们将此表称为 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 销售所有游戏机,而亚运会商场只销售亚洲游戏机。我们需要将 shop 和 product 表中的主键映射到 ShopProduct 表中。

下面是我们将如何进行映射。在我的示例中,American Games R Us 的 ShopID 值为 1(这是主键值),我可以看到 XBOX360 的值为 3,并且商店以 159.99 美元的价格列出了 XBOX360

通过执行以下代码,您将完成映射:

INSERT INTO ShopProduct VALUES(1,3,159.99)

现在我们想将所有产品添加到欧洲游戏体验店。在此示例中,我们知道 Europe Gaming Experience 商店的 ShopID 为 3,由于它销售所有游戏机,我们需要将 ProductID 1、2 和 3 插入到映射表中。假设欧洲游戏体验店的游戏机(产品)价格如下: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

至此,您已将两个商店及其产品映射到映射表中。好的,那么现在我如何将所有这些放在一起以显示用户正在浏览该网站?假设您想在网页上向用户展示欧洲博彩体验的所有产品——您需要执行以下查询:

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

现在举最后一个例子,假设您的网站有一项功能,可以找到最便宜的主机价格。一位用户要求找到 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 的商店的列表,首先是最便宜的商店,依此类推。

你会注意到我没有添加亚运商店。作为练习,将带有以下产品的亚运商店添加到映射表中:亚运商场以 99.99 美元的价格出售 Wii 游戏机,以 159.99 美元的价格出售 PS3 游戏机。如果您通过此示例工作,您现在应该了解如何建模多对多关系。

我希望这对您的数据库设计之旅有所帮助。

于 2012-06-04T07:06:06.030 回答
3

您将需要从输入构建 CREATE TABLE 语句,然后执行它。

一个简单的例子:

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);
于 2012-06-04T07:04:06.120 回答
1

首先,您似乎在混合表变量和表。

无论哪种方式,您都不能这样传递表的名称。您必须使用动态 TSQL 来执行此操作。

如果您只想声明一个表变量:

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

您想要创建存储过程来动态创建表的事实可能表明您的设计是错误的。

于 2012-06-04T07:04:50.297 回答
1

这是一种使用 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);';

执行如下:

exec(@cmd);
于 2018-06-04T06:38:49.293 回答
0

您可以编写以下代码:-

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

执行为: -

执行 spCreateTable

于 2015-07-16T17:32:57.597 回答