不能在 PIVOT 运算符中使用,因为它对于 NULL 不是不变的

发布于 2024-11-30 12:10:31 字数 2089 浏览 1 评论 0原文

我在 SQL Server 2008 中为字符串列创建一个聚合函数。C

# 代码如下所示:

using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;

[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize = 8000)]
public struct strconcat : IBinarySerialize
{
    private List<String> values;

    public void Init()
    {
        this.values = new List<String>();
    }

    public void Accumulate(SqlString value = new SqlString())
    {
        this.values.Add(value.Value);
    }

    public void Merge(strconcat value)
    {
        this.values.AddRange(value.values.ToArray());
    }

    public SqlString Terminate()
    {
        return new SqlString(string.Join(", ", this.values.ToArray()));
    }

    public void Read(BinaryReader r)
    {
        int itemCount = r.ReadInt32();
        this.values = new List<String>(itemCount);
        for (int i = 0; i <= itemCount - 1; i++)
        {
            this.values.Add(r.ReadString());
        }
    }

    public void Write(BinaryWriter w)
    {
        w.Write(this.values.Count);

        foreach (string s in this.values)
        {
            w.Write(s);
        }
    }
}

在 SQL 中查询:

DECLARE @listCol NVARCHAR(2000)

SELECT  @listCol = STUFF(( SELECT '],[' + A.Name
                        FROM Attribute A,Category C
                        WHERE A.CategoryId = C.Id
                        ORDER BY A.DisplayOrder DESC
                        FOR XML PATH('')), 1, 2, '') + ']'
DECLARE @query NVARCHAR(2000)
SET @query =

N'SELECT * FROM (SELECT P.*,A.Name AttributeName,PA.OriginalValue FROM Product P,Product_Attribute PA, Attribute A WHERE P.Id = PA.ProductId AND A.Id = PA.AttributeId) src
PIVOT 
(
    dbo.strconcat(OriginalValue) FOR AttributeName 
    IN ('+@listCol+')) AS pvt'

EXECUTE (@query)

但 SQL Server 返回错误:

消息 406,第 16 级,状态 1,第 5 行
dbo.strconcat 不能在 PIVOT 运算符中使用,因为它对于 NULL 不是不变的。

我用谷歌搜索但不知道如何修复它。

请帮我!

I create an aggregate function for string column in SQL Server 2008.

C# code look like this:

using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;

[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize = 8000)]
public struct strconcat : IBinarySerialize
{
    private List<String> values;

    public void Init()
    {
        this.values = new List<String>();
    }

    public void Accumulate(SqlString value = new SqlString())
    {
        this.values.Add(value.Value);
    }

    public void Merge(strconcat value)
    {
        this.values.AddRange(value.values.ToArray());
    }

    public SqlString Terminate()
    {
        return new SqlString(string.Join(", ", this.values.ToArray()));
    }

    public void Read(BinaryReader r)
    {
        int itemCount = r.ReadInt32();
        this.values = new List<String>(itemCount);
        for (int i = 0; i <= itemCount - 1; i++)
        {
            this.values.Add(r.ReadString());
        }
    }

    public void Write(BinaryWriter w)
    {
        w.Write(this.values.Count);

        foreach (string s in this.values)
        {
            w.Write(s);
        }
    }
}

And query in SQL:

DECLARE @listCol NVARCHAR(2000)

SELECT  @listCol = STUFF(( SELECT '],[' + A.Name
                        FROM Attribute A,Category C
                        WHERE A.CategoryId = C.Id
                        ORDER BY A.DisplayOrder DESC
                        FOR XML PATH('')), 1, 2, '') + ']'
DECLARE @query NVARCHAR(2000)
SET @query =

N'SELECT * FROM (SELECT P.*,A.Name AttributeName,PA.OriginalValue FROM Product P,Product_Attribute PA, Attribute A WHERE P.Id = PA.ProductId AND A.Id = PA.AttributeId) src
PIVOT 
(
    dbo.strconcat(OriginalValue) FOR AttributeName 
    IN ('+@listCol+')) AS pvt'

EXECUTE (@query)

But SQL Server returns an error:

Msg 406, Level 16, State 1, Line 5
dbo.strconcat cannot be used in the PIVOT operator because it is not invariant to NULLs.

I googled it but don't know how to fix it.

Please help me!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

尽揽少女心 2024-12-07 12:10:31

如果您的聚合对于空值不变,则需要在 SqlUserDefinedAggregateAttribute,类似于:

[SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize = 8000,
   IsInvariantToNulls = true)]

IsInvariantToNulls 属性将要求描述为:

由查询处理器使用,如果聚合对于空值不变,则此属性为 true。即S的聚合,{NULL}与S的聚合相同。例如MIN、MAX等聚合函数满足这个性质,而COUNT(*)则不满足。

看看您的聚合,我认为您可能需要在 Add 方法中做一些工作 - 如果传入的值为 null,也许不将其添加到列表中?

If your aggregate is invariant to nulls, you need to mark it as such in the SqlUserDefinedAggregateAttribute, something like:

[SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize = 8000,
   IsInvariantToNulls = true)]

The IsInvariantToNulls property describes the requirement as:

Used by the query processor, this property is true if the aggregate is invariant to nulls. That is, the aggregate of S, {NULL} is the same as aggregate of S. For example, aggregate functions such as MIN and MAX satisfy this property, while COUNT(*) does not.

Looking at your aggregate, I think you might need to do some work in your Add method - if the passed in value is null, maybe don't add it to the list?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文