2013-06-20 2 views
1

Учитывая следующую простую структуру:Хранимая процедура вставки значений в таблицу, используя табличные значения параметров

TABLE: Product (ProductId, ProductName) 

TABLE: Category (CategoryId, CategoryName) 

LINK TABLE: ProductId,CategoryId 

У меня есть тип таблицы, которую я хочу передать в хранимую процедуру для вставки значения в другую таблицу, если они не существуют.

CREATE TYPE StringList_TBLType AS TABLE (s NVARCHAR(255) NOT NULL PRIMARY KEY) 

Я хочу сделать следующее в хранимой процедуре, где я прохожу в ProductName и StringList_TBLType из категории имен

  1. выбрать все строки из моего StringList_TBLType
  2. Вставьте строку в ТАБЛИЦА ТАБЛИЦЫ, если она не существует
  3. Получить идентификатор вставленной или уже существующей категории
  4. Вставьте ProductId и CategoryId в LINK T СОСТОЯНИЕ.

Я мог бы, вероятно, бороться и что-то работать, но у меня мало опыта работы с MS SQL и хранимых процедур в целом, и я боюсь, что в конечном итоге я напишу очень неэффективный способ сделать это.

ответ

2

Вы можете использовать оператор MERGE для регистрации идентификаторов категорий.

DECLARE @changes TABLE (ChangeID VARCHAR(10), Id INTEGER); 
DECLARE @JustSomeRandomVariable INT; 

MERGE Category AS TARGET 
USING @data AS SOURCE 
    ON TARGET.Category = SOURCE.s 
WHEN NOT MATCHED THEN 
    INSERT ([Category]) 
    VALUES (SOURCE.s) 
WHEN MATCHED THEN 
    UPDATE SET @JustSomeRandomVariable = 1 
OUTPUT $action, inserted.Id INTO @changes; 

Случайная переменная в операторе слияния гарантирует, что обновления будут регистрироваться в переменной таблицы @changes.

Теперь вы можете использовать @changes для обновления таблицы ссылок.

INSERT INTO Link SELECT ProductID, ChangeID FROM @changes 

Просто получить требуемый ProductID с помощью простого запроса выбора.

EDIT:

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

@data является параметром StringList_TBLType вашей процедуры.

+0

Интересно ... Никогда не слышал о слиянии и раньше, но после некоторого чтения, это выглядит как стол @changes будет иметь только идентификаторы новых категорий ? Мне также нужны идентификаторы существующих категорий, так как оба нужно зайти в таблицу ссылок. – Trevor

+1

Я сделал тест для себя (SQL Server 2008 R2) и, добавив назначенный слишком «@ JustSomeRandomVariable» для обновлений, он фиксирует обновления в @changes также. – JodyT

+0

Ах, звучит так, будто я должен дать ему повод и посмотреть, что произойдет! – Trevor

0

Это то, что я хотел бы предложить (не тестировалось)

CREATE PROCEDURE AddProductToCategories 
@productname nvarchar(255), 
@categories StringList_TBLType READONLY 
AS 
BEGIN 

DECLARE @productId bigint --change to datatype of Product.ProductId 
SET @productId = (SELECT TOP 1 ProductId FROM Product WHERE ProductName = @productname) --What to do if your product names are not unique? 

IF @productId is not NULL 
BEGIN 

DECLARE cur CURSOR FOR (
    SELECT cat.CategoryName, cat.CategoryId, c.s 
    FROM @categories c 
     RIGHT OUTER JOIN Category cat on c.s = cat.CategoryName 
) 

DECLARE @id as bigint --change to datatype of Category.CategoryId 
DECLARE @name as nvarchar(255) --change to datatype of Category.CategoryName 
DECLARE @categoryNameToAdd as nvarchar(255) 

OPEN cur 
FETCH NEXT FROM cur INTO @name, @id, @categoryNameToAdd 

WHILE @@FETCH_STATUS = 0 
BEGIN 
    IF @id is NULL 
    BEGIN 
     --category does not exist yet in table Category 
     INSERT INTO Category (CategoryName) VALUES (@categoryNameToAdd) 
     SET @id = SCOPE_IDENTITY() 
    END 

    INSERT INTO ProductsCategories --your link table 
    (ProductId, CategoryId) 
    VALUES 
    (@productId, @id) 


    FETCH NEXT FROM cur INTO @name, @id, @categoryNameToAdd 
END --cursor 


CLOSE cur 
DEALLOCATE cur 
END --IF @productId 
END --sproc 
+1

Я бы не использовал курсоры, если нет другого пути. И если вам действительно нужны курсоры, вам нужно подумать дважды, если вы хотите решить проблему в T-SQL. – JodyT

+0

Из-за производительности? – bvgheluwe

+1

В общем, они требуют большего количества кода (сложнее поддерживать) и имеют худшую производительность. – JodyT