【问题标题】:How to write "Tagging" query in SQL?如何在 SQL 中编写“标记”查询?
【发布时间】:2009-02-17 17:13:12
【问题描述】:

我正在我的网络应用程序中添加“标记”功能。我的应用程序表结构如下;

Tag:

(TagId INT IDENTITY, TagName VARCHAR(60))

TaggedRecords:

(TaggedId INT IDENTITY, TagId, TaggedRecordId)

现在,我希望当任何人向任何记录添加标签时,应使用单个 sql 查询或使用存储过程执行以下操作;

  • 标签是否已经存在于“标签”表中?
  • 如果标签存在,那么它会在“TaggedRecords”表中插入一行
  • 如果标签不存在,则先在“Tag”表中插入标签,然后获取新添加的标签的ID,并在“TaggedRecord”表中插入一条记录

基本上,我对使用单个查询或最多两个 sql 查询来执行这些操作更感兴趣。我不想在 sql 存储过程中创建多个 If-Else 条件。

谢谢,

【问题讨论】:

    标签: sql sql-server-2005 tsql stored-procedures


    【解决方案1】:

    这个怎么样...

    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 用法的另一个示例,请参阅我在 this link 的帖子

    编辑

    根据以下版本的 cmets,此版本使用 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。

    嗯,任君选择 - 或者在音量下测试这两种方法:)

    【讨论】:

    • 我们可以实现 EXISTS 子句以使其更简单吗??
    • 不是真的,因为我们需要从表中检索 tagid 并且 EXISTS 只返回一个布尔值而不是 id - 这是可能的,但无论如何您都必须在插入中进行选择查询。这取决于您的估计使用量——您会更多地使用现有标签还是新标签?
    • 已经考虑了更多 - 您最好将选择移动到插入中并使用 EXISTS,因为从长远来看,人们更有可能使用现有标签而不是新标签?
    【解决方案2】:

    您基本上已经掌握了,但是您可以通过更改顺序来提高效率。这是您的过程的一些伪 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:

     插入标签(标签名称)
        输出已插入.TagId INTO @TagId
        值(@NewTag);
    • 标签是唯一的,因此您应该能够将其选择回来:
     插入标签 (TagName) 值 (@NewTag);
        从标签中选择 TagId,其中 TagName = @NewTag INTO @TagId;

    如果您想 SELECT 它退出,如果您使用 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
    

    【讨论】:

    • 什么“插入新标签,将新的TagId返回到@TagId”这意味着,我们将如何在@TagId变量中获取新生成的Id。
    • "IF @TagId IS NULL THEN"
    【解决方案3】:

    请问为什么? if/else 有限制吗? :)

    看看你的情况,它看起来不需要超过 1 个 IF 子句。

    【讨论】:

    • 你说得对,对使用 IF 子句没有限制,但实际上我在某处看到了一个查询,它使用 EXISTS 子句执行类似于我正在尝试的操作? techonthenet.com/sql/exists.php
    • 但是条件是 EXISTS 子句会执行得更好然后 If 或 If 会执行得更好。
    【解决方案4】:

    您在标记表中使用合并,然后在标记记录表中插入。这是 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 link

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-04
      • 1970-01-01
      • 1970-01-01
      • 2017-12-12
      • 2013-01-17
      • 1970-01-01
      相关资源
      最近更新 更多