2012-06-04 2 views
15

код, как это, но это не так:T-SQL Как динамически создавать таблицы в хранимых процедурах?

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

Не могли бы вы сказать мне, как с этим бороться? Меня это действительно беспокоит.

ответ

37

Вы используете переменную таблицы, то есть вы должны объявить таблицу. Это не временная таблица.

Вы создаете временную таблицу следующим образом:

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

Вы объявляете переменную таблицы следующим образом:

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

Обратите внимание, что таблица температуры объявляется с помощью # и таблицы переменных объявляется с использованием a @. Ознакомьтесь с разницей между табличными переменными и временными таблицами.

UPDATE:

Основываясь на ваш комментарий ниже вы на самом деле пытаются создать таблицы в хранимой процедуре. Для этого вам нужно будет использовать динамический 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 

Эта таблица немного сложнее первого примера, не так много. Хранимая процедура будет намного сложнее иметь дело.Поэтому, хотя этот подход может работать и для небольших таблиц, он быстро будет неуправляемым.

Создание таблиц требует планирования. Когда вы создаете таблицы, их следует размещать стратегически в разных файловых группах. Это делается для того, чтобы вы не вызывали конкуренцию со стороны IO. Как вы решаете масштабируемость, если все создано в основной группе файлов.

Не могли бы вы объяснить, почему вам нужно создавать таблицы динамически?

UPDATE 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' 

Если вы выполняете SELECT * FROM Shop вы, вероятно, увидите следующее:

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

правой, так что теперь давайте перейдем на стол Items (товаров). Поскольку товары/товары - это продукты различных компаний, я собираюсь назвать продукт таблицы. Вы можете выполнить следующий код, чтобы создать простую таблицу продуктов.

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 

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 

Итак, давайте предположим, что американские игры R Us магазин продает только американские консоли, Европа игровой опыт продает все консолей и Азиатских игр Emporium продает только азиаты мы должны были бы для отображения первичных ключей из таблиц магазина и продукта в таблицу ShopProduct.

Вот как мы собираемся сделать сопоставление. В моем примере у American Games R Us есть значение ShopID 1 (это значение первичного ключа), и я вижу, что XBOX360 имеет значение 3, а в магазине указано XBOX360 за 159.99

Выполняя следующий код:

INSERT INTO ShopProduct VALUES(1,3,159.99) 

Теперь мы хотим добавить все товары в магазин Gaming Experience Europe. В этом примере мы знаем, что в магазине 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 

На данный момент вы отображенные два магазина и продукты их в таблицу отображения. Итак, теперь, как мне собрать все это, чтобы показать пользователю просмотр веб-сайта. Допустим, вы хотите показать всему продукту для европейского игрового опыта пользователю на веб-странице, вам нужно будет выполнить следующий запрос.

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 с самым дешевым магазином первыми и так далее.

Вы заметите, что я не добавил магазин азиатских игр. В качестве упражнения добавьте магазин азиатских игр в таблицу сопоставления со следующими продуктами. Азиатские игры Emporium продают консоль для игр Wii за $ 99,99 и консоль PS3 за $ 159.99. Если вы выполните этот пример, вы должны понять, как моделировать отношения многих и многих.

Надеюсь, это поможет вам в ваших путешествиях с дизайном базы данных.

+0

thanx, мне нужна процедура для создания таблиц, а имена таблиц и столбцов - это параметры, переданные процедуре. Например: sp_createATable 'tablename', 'id name age gender' – tmj

+0

Ваш комментарий мне очень помогает. Огромное спасибо. И по этой причине мне нужно динамически создавать таблицы, я хочу имитировать платформу электронной коммерции, и я разработал таблицу для сбора всей информации о товарах. И система строит таблицу для каждого магазина, чтобы хранить товары, которые он имеет после регистрации магазина. Я знаю, что должны быть другие лучшие планы, но я не думаю об одном =. =! Любое предложение? – tmj

+0

Обратитесь к разделу 2 обновленного ответа, чтобы получить лучший способ добиться того, что вы делаете. – Namphibian

2

Вам нужно будет создать инструкцию 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); 
2

Во-первых, вы, кажется, смешивания таблицы переменных и таблиц.

В любом случае, вы не можете передать имя таблицы так. Для этого вам придется использовать динамический TSQL.

Если вы просто хотите, чтобы объявить переменную таблицы:

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

Тот факт, что вы хотите создать хранимую процедуру для динамического создания таблицы может предложить ваш дизайн является неправильным.

+0

Em ... но почему это неправильно дизайн, любые недостатки, не могли бы вы подсказать мне ? – tmj

0

Вы можете написать следующий код: -

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

выполнить его как: -

Exec spCreateTable