Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 将关联表展平到多值列?_Sql_Sql Server_Sql Server 2008_Tsql - Fatal编程技术网

Sql 将关联表展平到多值列?

Sql 将关联表展平到多值列?,sql,sql-server,sql-server-2008,tsql,Sql,Sql Server,Sql Server 2008,Tsql,我有一个只包含产品ID和类别ID的表(产品可以在多个类别中)。如何将类别ID展平到产品列中,以此结束: id | name | desc | categories 1 | test1 | lorem | 1,3,4,23 2 | test2 | ipsom | 4,6,24 这就像我需要循环到一个单独的表中的categories列一样。我如何才能做到这一点,或者有更好的方法吗?我建议使用。我相信会是这样的: select productid, categoryid, row_numb

我有一个只包含产品ID和类别ID的表(产品可以在多个类别中)。如何将类别ID展平到产品列中,以此结束:

id | name | desc | categories
1 | test1 | lorem | 1,3,4,23
2 | test2 | ipsom | 4,6,24
这就像我需要循环到一个单独的表中的categories列一样。我如何才能做到这一点,或者有更好的方法吗?

我建议使用。我相信会是这样的:

select productid, categoryid, 
    row_number() over (partition by id order by categoryid) as rownum
into #tabletorecurse
from TABLENAME

with finaloutput as
(
    select productid as id, name, desc, categoryid as categories, rownum
    from #tabletorecurse
        join PRODUCTTABLE
            on PRODUCTTABLE.id = #tabletorecurse.productid
    where rownum = 1

    union all

    select tr.id, tr.name, tr.desc, 
        finaloutput.categories + ', ' + tr.categoryid, tr.rownum
    from #tabletorecurse as tr
        join finaloutput 
            on finaloutput.rownum + 1 = tr.rownum 
                and finaloutput.id = tr.productid
)
select id, name, desc, categories
from finaloutput
    join 
    (
        select max(rownum) as maxrow, id
        from finaloutput
        group by id 
    ) as maxvalues
       on maxvalues.id = finaloutput.id 
           and maxvalues.maxrow = finaloutput.rownum

在MSSQL中没有内置的方法来实现这一点

很好地描述了如何实施变通方法。

我创建了一个函数,它接受
varchar
列,并返回所有由逗号分隔的值。换句话说,它将几个字符串连接到一个逗号分隔的列表中。我确信它的性能比任何T-Sql技巧都要好

与任何聚合函数一样,它可以与
分组依据
结合使用。例如:

SELECT id, name, desc, JoinStrings(CONVERT(VARCHAR(20), category_id))
FROM product p
INNER JOIN category_products c ON p.category_id = c.category_id
GROUP BY id, name, desc
以下是在Sql Server 2008中创建CLR程序集的C代码:

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;


[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToDuplicates=false, IsInvariantToOrder=false, IsInvariantToNulls=true, MaxByteSize=-1)]
public struct JoinStrings : IBinarySerialize
{
    private char[] sb;
    private int pos;
    public void Init()
    {
        sb = new char[512000];
        pos = 0;
    }

    public void Accumulate(SqlString Value)
    {
        if (Value.IsNull) return;
        char[] src = Value.ToString().ToCharArray();
        Array.Copy(src, 0, sb, pos, src.Length);
        pos += src.Length;
        sb[pos] = ',';
        pos++;
    }

    public void Merge(JoinStrings Group)
    {
        Accumulate(Group.Terminate());
    }

    public SqlString Terminate()
    {
        if (pos <= 0) 
            return new SqlString();
        else
            return new SqlString(new String(sb, 0, pos-1));
    }

    public void Read(System.IO.BinaryReader r)
    {
        this.Init();
        pos = r.ReadInt32();
        r.Read(sb, 0, pos);
    }

    public void Write(System.IO.BinaryWriter w)
    {
        w.Write(pos);
        w.Write(sb, 0, pos);
    }
}
CREATE AGGREGATE [dbo].[JoinStrings]
(@s [nvarchar](4000))
RETURNS[nvarchar](max)
EXTERNAL NAME [YouAssemblyName].[JoinStrings]
使用函数。
这将查找文本,因此您需要进行调整。
联合只是为了放一个,。
这是一个大规模的生产应用程序—它工作正常,速度很快。
由于功能缓慢,Justin Pony对功能提出了质疑
我正在访问一些百万条记录的表,但只返回100行。
该函数仅应用于100行

用法:

select top 5 sID, ( select [dbo].[JoinMVEnum](docSVsys.sID, '140') ) as [Flag Issue]
from docSVsys
作用

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE FUNCTION [dbo].[JoinMVText]
(
   @sID int,
   @fieldID tinyint
)
RETURNS VARCHAR(MAX)
AS 
BEGIN
    DECLARE @MVtextList varchar(max)
    SELECT @MVtextList = COALESCE(@MVtextList + '; ', '') + docMVtext.value
    FROM docMVtext with (nolock) 
    WHERE docMVtext.sID = @sID and fieldID = @fieldID
    RETURN @MVtextList
END

GO

我从来没有听说过SQL标量函数速度快?SQL是一种基于集合的语言,通常一次只能发出一种臭味。至少当你进入100万行(OP可能会或可能不会击中)时,@JustinPihony在你批评之前,测试一下你提出的方法。我用它来对付100万行和6 mv列,响应时间不到一秒。将数据推送到#temp和union也没有那么快。不过,CTE是按设置逻辑运行的。函数每行运行一次。不过,这两种方法都有效,OP选择了一种:)是的,CTE按设定运行。是的,函数按行运行,但这是按输出行运行,而不是按表行运行。针对我170万的数据,仅步骤1就需要2秒,而基于函数的查询只需0.4秒。您有1个临时、5个选择、3个联接和1个并集。所以一个集合运算是快速的——这只是很多集合运算。检索集合所基于的所有170万行将非常接近。根据一个大表和基于wins的函数检索1000条记录。大多数查询的本质是检索表的子集。不过,通常CTE的性能相当好。慢的部分是什么?如果它支持列排序和MySQL中的自定义分隔符,那就好了:
GROUP_CONCAT(klascode,(',name,)“ORDER BY klascode ASC separator',”)