如何从 .cfc 文件中的一个 DELETE 语句中的多个表中删除?

How to delete from multiple tables in one DELETE statement in a .cfc file?

我有两个 table。设备 table 和位置 table。设备 table 中只能有一个设备,但在位置 table 中可以有多个具有多个位置的设备。

如果用户删除设备,我还需要从位置 table 中删除具有相同 ID 的位置。

有没有办法从 cfc 页面中删除语句(使用 sql 服务器)中的多个 tables?

我尝试在执行初始删除时写一个 <cfif>,以检查是否有记录被删除,如果有,运行 下一个删除语句,从 table。

我也试过用这个格式。

delete T1, T2
from T1 
inner join T2 on T1.device_id = T2.device_id
where T2.device_id = '111';

T1 = 设备 table,T2 = 位置 table

<cfif ARGUMENTS.submitButton eq 'btn_Delete'>
   <cfquery name="DeleteDevice" datasource="#session.dsn#" maxRows=1 >
        DELETE from #session.tq#device
        WHERE device_id = <cfqueryparam value="#formStruct.deviceId#" cfsqltype="CF_SQL_VARCHAR">
    </cfquery>
 </cfif>

<cfif DeleteDevice.RecordCount eq 1>
<cfquery name="DeleteLocation" datasource="#session.dsn#" maxRows=1 >
        DELETE from #session.tq#device_location_xref
        WHERE device_location_xref_recno=<cfqueryparam value="#formStruct.deviceId#" cfsqltype="CF_SQL_VARCHAR">
</cfquery>

你能做这样的事情吗

<cfquery>
DECLARE @device_id varchar(20) = <cfqueryparam value="#formStruct.deviceId#" cfsqltype="CF_SQL_VARCHAR">

DELETE
FROM T1
WHERE device_id = @device_id 

DELETE
FROM T2
WHERE device_id = @device_id 
</cfquery>

(我认为将所有有用的评论合并到社区维基答案下会有所帮助)

你能在一个语句中从多个 table 中删除吗?

不适用于 SQL 服务器,不。一些数据库,如 MySQL,支持 multi-table delete statements。 SQL服务器没有。您将需要多个删除语句。但是,如果目标只是删除记录,则差别不大。

当前代码有什么问题?

  • 当前代码无法运行的原因有多种。首先,初始 delete 查询仅在提交表单时执行。第二个代码块引用同一个查询,但首先不验证它是否确实存在。如果尚未提交表单,这将导致未定义的变量错误。

  • 其次,更重要的是,DELETE 语句从不 return 一个 "query" 对象,用 CF 的说法。所以即使第一个查询did执行了,查询变量DeleteDevice也永远不会存在。同样,当代码尝试在此处使用它时会导致未定义的变量错误:<cfif DeleteDevice.RecordCount eq 1>.

    尽管除非有更多内容,否则...cfif 在 IMO 中没有什么用处。如果 deviceID 存在记录,它们将被删除。如果没有,什么也不会发生。跳过第二次删除的任何微不足道的节省都被增加的代码复杂性所抵消。

  • 最后,虽然它不会导致硬错误,但 maxRows=1 并没有按照您的想法进行。它对 DELETE 语句没有任何影响,也不会阻止 DELETE 语句删除多条记录。 maxRows 属性仅适用于 return 一个 "query" 对象的语句,并用于限制该查询中包含的记录数。

那么如何处理多个删除语句?

由于 SQL 服务器不支持 multi-table DELETE 语句,您将需要两个语句 - 无论如何。有几种构造 SQL 的方法,每种方法各有利弊。但是,在 所有 情况下,您应该使用 transaction 对相关语句进行分组,并确保所有内容作为一个单元完成或失败

  • 多个cfquery的

    只需 运行 您的两个查询,一个接一个,在一个事务中。尽管交换语句顺序,如 。由于 FK 约束的可能性,最好先从 child/FK table 中删除,最后从 primary/PK table 中删除。

    <cftransaction> <cfquery datasource="#session.dsn#"> DELETE FROM device_location_xref WHERE ... </cfquery> <cfquery datasource="#session.dsn#"> DELETE FROM device WHERE ..... </cfquery> </cftransaction>

  • 单个 cfquery 中的多个语句

    作为 demonstrates, placing both SQL statements within a single cfquery tag is another option. However, keep in mind 。出于安全原因,可以在 db/driver 级别禁用多个语句。所以这种方法可能不适用于所有环境。

    <cftransaction> <cfquery datasource="#session.dsn#"> DELETE FROM device_location_xref WHERE ... DELETE FROM device WHERE ..... </cfquery> </cftransaction>

  • SQL 存储过程

    另一种选择是:将sql逻辑放入存储过程中。一般来说,存储过程更适合复杂的sql操作,而且不像cfquery,它们可以return多个结果集。

    CREATE PROCEDURE DeleteDevice
      @deviceID VARCHAR(50)
    AS
    BEGIN
        -- minimal error handling for demo only
        BEGIN TRAN
            DELETE FROM device_location_xref
            WHERE device_location_xref_recno = @deviceID
    
            DELETE from device
            WHERE device_id = @deviceID
    
        END TRAN
    
    END
    

    然后使用 cfstoredproc 而不是 cfquery 调用它。

    <cfstoredproc procedure="DeleteDevice" datasource="#ds#"> 
       <cfprocparam type="in" value="#formStruct.deviceId#" 
              cfsqltype="cf_sql_varchar"> 
    </cfstoredproc>
    

软删除与硬删除

最后,另一种 is a "soft-delete". Instead of physically removing the records, you could add a BIT column to the table(s). Then UPDATE that column flag whenever you need to mark a record as deleted. See this thread讨论soft-deletes的优缺点。

      UPDATE TableName
      SET    IsDeleted   = 1
      WHERE  TheIDColumn = 12345

我会在一个 cfquery 语句中从两个表中删除,因为第二次删除不依赖于第一次删除。

  <cfif comparenocase(ARGUMENTS.submitButton, 'btn_Delete') EQ 0> <!--- bit quicker to use compare --->
    <cfquery name="DeleteDevice" datasource="#session.dsn#"> 
    <!--- delete from first table --->
    DELETE FROM #session.tq#device
    WHERE device_id = <cfqueryparam value="#formStruct.deviceId#" cfsqltype="CF_SQL_VARCHAR">;

<!--- delete from second table --->    
    DELETE FROM #session.tq#device_location_xref
    WHERE device_location_xref_recno=<cfqueryparam value="#formStruct.deviceId#" cfsqltype="CF_SQL_VARCHAR">
    </cfquery>
    </cfif>