SQL Server 2008 - CAST 到 nvarchar 不起作用

Posted

技术标签:

【中文标题】SQL Server 2008 - CAST 到 nvarchar 不起作用【英文标题】:SQL Server 2008 - CAST to nvarchar not working 【发布时间】:2015-09-11 10:36:57 【问题描述】:

我有以下 SQL 语句作为触发器的一部分,它不工作并且无法弄清楚原因:

DECLARE @Orderid INT
DECLARE @CountOfOrderItems INT
DECLARE @EmployeeID INT
DECLARE @EmployeeName NVARCHAR

SELECT @Orderid = DELETED.id

SET @CountOfOrderItems = (select count(*) from OrderDetails where OrderID = @Orderid)

SET @EmployeeName = (SELECT Firstname + ' ' + Lastname from Employees where employees.id = 
                      (SELECT employeeid from Orders where Orders.id = @Orderid))

        INSERT INTO applicationlog (Sourceobject,Logtype,Message)
        VALUES ('Orders table',
                'Order deleted',
                'Order with ' + CAST(@CountOfOrderItems as varchar) + ' items deleted by '+ CAST(@EmployeeName as nvarchar))

applicationlog 表的列数据类型都是 nvarchar(255) 用于 sourceobject 和 logtype 和 nvarchar(max) 用于消息。

问题是,当我包含CAST(@EmployeeName as nvarchar) 位时,消息列中没有输入任何内容,并且显示为空。在其他两列中输入数据。将员工名称转换为 varchar 也不起作用。

当我删除上面以粗体显示的位并使用以下代码时,它可以工作,并且 countoforderitems 的转换工作。

INSERT INTO applicationlog (Sourceobject,Logtype,Message)
VALUES ('Orders table',
        'Order deleted',
        'Order with ' + CAST(@CountOfOrderItems as varchar) + ' items deleted')

我不知道为什么,希望得到一些帮助,因为我需要记录正在删除记录的用户。

谢谢

更新

感谢所有回复的人。我将 employeename 声明为 VARCHAR(255) 并将插入语句编辑为

        INSERT INTO applicationlog (Sourceobject,Logtype,Message)
    values ('Orders table','Order deleted','Order with ' + CAST(@CountOfOrderItems as varchar(255)) + ' items deleted by ' + coalesce(@EmployeeName,''))

现在所有信息都在那里,除了我认为返回空字符串的@Employeename,即使员工存在于表中。所以在最后一列中,我现在有 “3 个项目被“删除”强>

哪个比之前的null好,但是为什么@Employeename是空白的呢?

【问题讨论】:

@EmployeeName 在声明中已经是 NVARCHAR,你为什么要转换它?如果它是空的,你的整个连接将是空的,你必须做一些检查并添加空字符串,如果它是空的 - COALESCE(@EmployeeName,'')......同样就像提到你应该每次设置一个长度,当你声明它没有长度,默认为 1 您的触发器似乎已损坏 - deleted 是一个可能包含 0、1 或 多个 行的表。将值从它分配给一个标量变量,SELECT @Orderid = DELETED.id 是有缺陷的(如果这甚至有效 - 我原以为您仍然需要该查询的 FROM 子句)。 Damien - 我的理解是触发器在一条记录(即一行被删除)时运行?如果我错了,请纠正我。是的,SELECT @orderid 确实返回了一个值,并且语法看起来确实很奇怪,但是这里还有其他触发器可以使用它并且工作正常。干杯 【参考方案1】:

您至少在三个地方使用了没有长度的nvarchar(或varcharncharchar)。 不要这样做。默认长度因上下文而异。所以:

DECLARE @EmployeeName NVARCHAR

真的是:

DECLARE @EmployeeName NVARCHAR(1)

CAST(@CountOfOrderItems as varchar)

真的是:

CAST(@CountOfOrderItems as varchar(30))

(好吧,这应该没问题)。

因此,请明确说明长度。您不需要为字符串连接转换 @EmployeeName。而且,您不需要使用set,因为您可以在select 语句中设置变量的值:

DECLARE @Orderid INT;
DECLARE @CountOfOrderItems INT;
DECLARE @EmployeeID INT;
DECLARE @EmployeeName NVARCHAR(255);

SELECT @Orderid = DELETED.id;  -- This looks strange.  I think you are missing a `from` clause

select  @CountOfOrderItems = count(*)
from OrderDetails
where OrderID = @Orderid);

SELECT @EmployeeName = Firstname + ' ' + Lastname
from Employees
where employees.id = (SELECT employeeid from Orders where Orders.id = @Orderid));

INSERT INTO applicationlog (Sourceobject, Logtype, Message)
    VALUES ('Orders table',
            'Order deleted',
            'Order with ' + CAST(@CountOfOrderItems as varchar(8000)) + ' items deleted by '+ @EmployeeName ;

或者,我会省去所有中间的东西,然后做:

INSERT INTO applicationlog (Sourceobject, Logtype, Message)
    SELECT 'Orders table', 'Order deleted',
           replace(replace('Order with @n items deleted by @by',
                           '@n', count(od.orderid)
                          ), '@by', e.Firstname + ' ' + e.Lastname
                  )
    FROM deleted d JOIN
         orders o
         on d.id = o.orderId JOIN
         employees e
         on o.employeeid = e.employeeid LEFT JOIN
         orderdetails od
         on od.orderid = o.orderid;

我认为单个查询可以更好地显示您正在做的事情的意图,并且您不需要发出一堆查询并分配变量。

【讨论】:

感谢您的回复戈登。我尝试了您的单一查询解决方案,但出现错误。我在上面编辑了一些表名,但仍然出现 2 个错误,都与名字和姓氏有关 - 错误是“列 'employees.Lastname' 在选择列表中无效,因为它不包含在聚合函数或 GROUP 中BY 子句。” 我编辑了这个位 FROM deleted d JOIN orders o on d.id = o.Id JOIN employees e on o.employeeid = e.id LEFT JOIN orderdetails od on od.orderid = o.id 【参考方案2】:

看起来您在这里混合了数据类型。如果您希望它是 nvarchar,那么它都需要是 Nvarchar。您还应该像这样指定您想要的长度:

VALUES ('Orders table',
                'Order deleted',
                N'Order with ' + CAST(@CountOfOrderItems as Nvarchar(10)) + N' items deleted by '+ CAST(@EmployeeName as nvarchar(10)))

说了这么多,我不知道为什么你已经将 @EmployeeName 声明为 Nvarchar,而你已经将它声明为 Nvarchar,这似乎是一个多余的过程。

如果您的 @EmployeeName 为 null,它也会为整个字符串显示 null,要解决此问题,您可以在查询顶部使用以下语句:

SET CONCAT_NULL_YIELDS_NULL OFF

【讨论】:

以上是关于SQL Server 2008 - CAST 到 nvarchar 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL Server 2000/2005/2008 中使用 FLOAT 转换小数位数

SQL Server 2008 计划缓存几乎总是空的

转置查询创建节点 (SQL Server 2008)

将 Nvarchar 转换为 Int 失败的 SQL Server 2008

在 SQL Server 2008 中将 NVARCHAR 转换为 INT 数据类型

SQL Server 2008 R2 数据类型转换错误