Как написать запрос тегов в SQL? - PullRequest
3 голосов
/ 17 февраля 2009

Я добавляю функцию тегирования в свое веб-приложение. Мои таблицы приложений имеют следующую структуру:

Tag:

(TagId INT IDENTITY, TagName VARCHAR(60))

TaggedRecords:

(TaggedId INT IDENTITY, TagId, TaggedRecordId)

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

  • Метка уже присутствует в таблице "Метка" или нет?
  • Если тег присутствует, он вставляет строку в таблицу «TaggedRecords»
  • В противном случае, если тег отсутствует, сначала вставьте тег в таблицу «Tag», а затем получите идентификатор вновь добавленного тега и вставьте запись в таблицу «TaggedRecord»

По сути, меня больше интересует выполнение этих действий с использованием одного или максимум двух запросов sql. Я не хочу делать несколько условий If-Else в хранимой процедуре sql.

Спасибо

Ответы [ 4 ]

1 голос
/ 17 февраля 2009

Вы в основном получили его, но вы можете сделать его немного более эффективным, изменив порядок. Вот некоторый псевдо-SQL-код для вашей процедуры:

SELECT TagId FROM Tag WHERE TagName = @NewTag into @TagId

IF @TagId IS NULL THEN
    INSERT new tag, returning the new TagId into @TagId

INSERT new record into TaggedRecords

Не знаю, почему вы так против использования предложений if ...


Чтобы получить новый сгенерированный TagId в переменную, у нас есть два варианта, так как вы используете MSSQL:

  • Используйте команду OUTPUT :
    INSERT INTO Tag (TagName) 
    OUTPUT Inserted.TagId INTO @TagId 
    VALUES (@NewTag);
  • Теги уникальны, поэтому вы можете просто выбрать его обратно:
    INSERT INTO Tag (TagName) VALUES (@NewTag);
    SELECT TagId FROM Tag WHERE TagName = @NewTag INTO @TagId;

Если вы хотите ВЫБРАТЬ его обратно, процедура может выглядеть лучше, если вы используете предложение IF EXISTS, но по сути вы выполняете ту же работу в любом случае:

IF NOT EXISTS(SELECT TagId FROM Tag WHERE TagName = @NewTag)
BEGIN
    INSERT INTO Tag (TagName) VALUES (@NewTag);
    SET @TagId = (SELECT TagId FROM Tag WHERE TagName = @NewTag);
END
ELSE
BEGIN
    SET @TagId = (SELECT TagId FROM Tag WHERE TagName = @NewTag);
END

INSERT new record into TaggedRecords
1 голос
/ 17 февраля 2009

Как насчет этого ...

CREATE PROC TagMe(@TagName VARCHAR(100),@TaggedRecordId INT)
AS

DECLARE @TagId INT

SET @TagId = SELECT TagId FROM Tag WHERE TagName = @TagName

IF @TagId IS NOT NULL
    BEGIN
    --Tag exists
        INSERT INTO TaggedRecords (TagId, TaggedRecordId) VALUES(@TagId,@TaggedRecordId)
    RETURN
    END
ELSE
    -- New tag
    BEGIN
        INSERT INTO Tag (TagName) OUTPUT inserted.id INTO @TagId VALUES(@TagName)
        INSERT INTO TaggedRecords (TagId, TaggedRecordId) VALUES(@TagId,@TaggedRecordId)
    RETURN
END

Не проверено, но теория должна быть обоснованной:)

Еще один пример использования OUTPUT см. В моем сообщении по адресу по этой ссылке

EDIT

Согласно комментариям ниже эта версия использует EXISTS ...

CREATE PROC TagMe(@TagName VARCHAR(100),@TaggedRecordId INT)
AS

DECLARE @TagId INT

IF EXISTS(SELECT TagId FROM Tag WHERE TagName = @TagName)
    BEGIN
    --Tag exists
        SET @TagId = SELECT TagId FROM Tag WHERE TagName = @TagName  
        INSERT INTO TaggedRecords (TagId, TaggedRecordId) VALUES(@TagId,@TaggedRecordId)
    RETURN
    END
ELSE
    -- New tag
    BEGIN
        INSERT INTO Tag (TagName) OUTPUT inserted.id INTO @TagId VALUES(@TagName)
        INSERT INTO TaggedRecords (TagId, TaggedRecordId) VALUES(@TagId,@TaggedRecordId)
    RETURN
END

Хотя я не уверен (я полагаю, что я спорю против себя здесь, но большая часть этого материала - ответ "это зависит"!). Этот пример на самом деле будет работать лучше для большего использования новых тегов, потому что он будет выполнять EXISTS только один раз и затем продолжаться, тогда как для существующего тега он будет выполнять EXISTS, а затем SELECT.

Хм, выбирайте сами - или протестируйте оба подхода в объеме:)

0 голосов
/ 17 февраля 2009

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

MERGE INTO TAG
USING (SELECT @tagname as TAGNAME FROM DUAL) RECORD
ON (TAG.TAGNAME = RECORD.TAGNAME)
WHEN NOT MATCHED THEN INSERT (TAG.TAGNAME) VALUES (@tagname);

INSERT INTO TAGGEDRECORDS(TAGID) VALUES (SELECT TAGID FROM TAG WHERE TAGNAME=@tagname);

Я думаю, что SQL Server также поддерживает некоторые более функциональные возможности в операторе MERGE, поэтому вы, вероятно, могли бы что-то сделать с предложением WHEN MATCHED (вставить в таблицу taggedrecords).

Выезд MSDN ссылка

0 голосов
/ 17 февраля 2009

Могу я спросить почему? Есть ли ограничение на if / else? :)

Глядя на ваш случай, не похоже, что ему понадобится более 1 предложения IF.

...