【问题标题】:How can I split a "Lastname, Firstname" data into separate lastname and firstname columns?如何将“姓氏,名字”数据拆分为单独的姓氏和名字列?
【发布时间】:2018-12-21 20:02:18
【问题描述】:

我们有一个表,其中有一个名为 fullname 的列,格式为“Lastname, Firstname”

我在表中添加了新列,以便我们可以将姓氏和名字分开,但我不知道该怎么做。下面的代码是我使用的,但“listFirst 不是可识别的内置函数名称。”

<cfquery name="splitname" datasource="dsn">
UPDATE dbo.employees
SET
  lastname = listFirst(fullname, ","),
  firstname = listRest(fullname, ", ")
</cfquery>

请指教。谢谢。

【问题讨论】:

  • 你不知道这会打开一罐蠕虫。

标签: sql-server tsql coldfusion


【解决方案1】:

这不应该在 ColdFusion 中完成。这是数据的问题,任何数据转换都应在 SQL Server 本身上处理。无需将数据拉回 CF,让 CF 操作数据,然后将操作后的数据传回 SQL。

正如在其他 cmets 中所提到的,通过进行此更改,您正在打开一大堆意想不到的蠕虫。名称可能非常难以使用。

此答案取决于您的姓名数据由姓氏、逗号和姓名的其余部分组成。它将修剪名字和姓氏并删除第一个逗号,但再次提防Garbage In, Garbage Out.。

您可以像这样将查询传递给 SQL:

<cfquery name="splitname" datasource="dsn">
    UPDATE dbo.employees
    SET lastname = ltrim(rtrim(left(fullname,charindex(',',fullname+',')-1)))
      , firstname = ltrim(rtrim(substring(fullname,charindex(',',fullname+',')+1,len(fullname))))
</cfquery>

您可以在https://dbfiddle.uk/?rdbms=sqlserver_2012&fiddle=85fc8abfdbb02c469e28c2e4dd1df4f5 的 SQL 中查看它。

【讨论】:

【解决方案2】:

一种简单的方法(这不是最好的方法。但它看起来像一次性的事情。所以应该没问题。)是选择行作为单独的查询并在循环中更新每一行.此外,您还需要在将列表函数传递给查询之前对其进行评估。还可以使用&lt;cfqueryparam&gt; 使字符串可以安全查询。

<cfquery name="splitname" datasource="dsn">
    SELECT empID, fullname 
    FROM dbo.employees
</cfquery>

<cfloop query="splitname">
    <cfquery datasource="dsn">
        UPDATE dbo.employees
        SET
            lastname = <cfqueryparam value="#trim(listFirst(splitname.fullname, ","))#" cfsqltype="varchar">,
            firstname = <cfqueryparam value="#trim(listlast(splitname.fullname, ","))#" cfsqltype="varchar">
        WHERE empID = <cfqueryparam value="#splitname.empID#" cfsqltype="varchar">
    </cfquery>
</cfloop>

【讨论】:

  • 我将不得不不同意。 cfquery 不应该在 cfloop 内。你会打败你的数据库。这是 MUCH 更适合在 SQL 本身中完成的事情。这不是真正的 ColdFusion 问题。
  • 当然,我应该包括这将工作,但它会比它需要的资源更难。 CF 不应该做这项工作。
  • 循环也明显变慢。这相当于使用游标......不是你想要对大量记录做的事情。虽然我明白这可能是一次性的,但仍然......
  • 几乎就像一个光标。 SQL 游标至少会停留在同一个数据库连接中。在cfloop 中,它将为每个循环重新连接到数据库,然后发送生成的查询,然后断开连接,然后重复直到循环完成。不止几行,这对您的系统来说可能是相当残酷的。
  • @RRK - 我听到你在说什么(并且知道你已经意识到了),但是在查询中循环之类的事情可能会对繁忙的服务器/应用程序产生非常负面的影响。涉及大量数据。由于我们并不总是知道提问者的经验水平,有多少数据 - 或者就此而言,未来还有谁会遇到答案并复制并粘贴它 - 最好不要假设。恕我直言,最好尽可能采用“最佳实践”。另外,事实证明,在这种情况下,这恰好是最简单的方法。所以双赢:-)
【解决方案3】:

除了Shawn's answer 之外,没有人提到的一件重要的事情是,您可能正在对 CF 中的查询存在误解。如果不小心,可能会对数据库产生一些非常不愉快的后果。

能够混​​合 CFML 和 SQL 并不意味着您的数据库服务器执行 CFML 代码

数据库服务器对 CFML 一无所知。事实上,数据库服务器甚至从未看到 cfquery 中的任何CFML 代码。所有 CFML(和/或 cfcript)代码都由 CF 应用程序服务器执行,甚至在数据库服务器进入图片之前。

那么,当您混合 CFML 和 SQL 时,实际会发生什么?从概念上讲,当代码执行时:

  1. CF 服务器尝试评估任何 CF 标记/功能并 将它们转换为文字值。然后将这些值连接起来 与其余的纯文本 SQL,形成一个大 SQL 字符串。

  2. CF 然后将该 SQL 字符串交给数据库执行

  3. 数据库服务器尝试执行 SQL 字符串并返回任何 结果到CF服务器

  4. CF 服务器将数据库结果转换为对象,例如 一个“查询”。

如您所见,两者绝对没有混合。 CF 负责处理任何 CFML。数据库处理任何 SQL。双胞胎永远不会相遇。

潜在的问题是什么?

进行这样的查询。它不会崩溃,但也不会产生预期的结果。

<cfset FORM.newAccountNumber = "1234,ABC">

<cfquery datasource="dsn">
   UPDATE someTable
   SET    AccountNumber = '#listFirst(FORM.newValue, ",")#'
</cfquery>

实际发生的事情是这样的。首先,CF 执行返回字符串“1234”的列表函数。

   #listFirst(variables.newValue, ",")#

CF 然后将该文字插入到 SQL 语句的其余部分中,生成以下内容:

    UPDATE someTable
    SET    AccountNumber = '1234'

当发送到数据库时,该语句将整个表中的每个单个帐号设置为相同的值:“1234”。几乎可以肯定,这不是预期的结果。

了解如何在查询中解释 CFML 代码有助于避免对您的数据库造成真正不愉快的后果。特别是如果您没有最近的备份...

【讨论】:

    【解决方案4】:

    我认为您的问题是您没有将 CF 函数放在 # 符号和引号中。

    <cfquery name="splitname" datasource="dsn">
    UPDATE dbo.employees
    SET
      lastname = '#listFirst(fullname, ",")#'
      , firstname = '#listRest(fullname, ", ")#'
    </cfquery>
    

    你真的应该使用。

    <cfquery name="splitname" datasource="dsn">
    UPDATE dbo.employees
    SET
      lastname = '<cfqueryparam cfsqltype="cf_sql_varchar" 
           value="#listFirst(fullname, ",")#">'
    </cfquery>
    

    作为最佳实践,我会在 SQL 语句之前清理变量并使用 trim 函数去除空格。

    <cfscript>
        firstname = trim(listFirst(fullname, ","));
        lastname = trim(listLast(fullname, ","));
    </cfscript>
    
    <cfquery name="splitname" datasource="dsn">
    UPDATE dbo.employees
    SET
      firstname = '<cfqueryparam cfsqltype="cf_sql_varchar" value="#firstname#">'
      , lastname = '<cfqueryparam cfsqltype="cf_sql_varchar" value="#firstname#">'
    </cfquery>
    

    此外,我们一直在尝试使用 SQL 的 DECLARE 语句来定义那里的变量。这使得向您的 DBA 提供复杂查询并让他们能够快速使用它们变得非常容易。此外,许多查询多次使用相同的变量,因此在列表顶部声明它们更加容易和清晰。

    <cfscript>
        firstname = listFirst(fullname, ",");
        lastname = listLast(fullname, ",");
    </cfscript>
    
    <cfquery name="splitname" datasource="dsn">
    
        DECLARE @FirstName varchar(50) = <cfqueryparam cfsqltype="cf_sql_varchar" value="#firstname#">
        DECLARE @LastName varchar(50) = <cfqueryparam cfsqltype="cf_sql_varchar" value="#lastname#">
    
        UPDATE dbo.employees
        SET
          firstname = @FirstName
          , lastname = @LastName
    
    </cfquery>
    

    【讨论】:

    • 我在您上次编辑之前尝试过,但我收到关于“全名”不是可识别变量的错误。我可以使用 RRK 的代码,但是谢谢!
    • @EvikJames - 在这种情况下,井号将无济于事,因为“全名”是数据库列,而不是 CF 变量,显然 CF 函数无法在数据库中执行。另外,即使它是 CF 变量,也要添加井号 wouldn't have the desired effect。旁注,看起来 cfqueryparam 周围有一些杂散的引号。 (我会自己修复它们,但我的编辑可能会被拒绝)。
    【解决方案5】:

    例如,Listgetat 可以解决问题;

    listgetat(fullname,1)  
    listgetat(fullname,2)
    

    【讨论】:

    • 您提供的代码是否适用于具有两个名字的记录,例如“Peggy Sue”?
    • 我仍然收到错误:[Macromedia][SQLServer JDBC Driver][SQLServer]'listgetat' is not a known built-in function name.
    • 肯定会的,它会在 , 上分裂,
    • 投反对票,因为这不能解决在 SQL 命令中使用 ColdFusion 函数的基本问题。它所做的只是使用不同的功能。
    • 在 SQL 命令中使用 ColdFusion 函数的基本问题 严格来说,不能在 in sql 命令中使用 CF 函数。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 1970-01-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 2013-03-26
    相关资源
    最近更新 更多