我想在一列中插入多行。
对于我这样的POS系统。
表A
:
Transaction ID| Item Code|Qty|Total|Transaction Date|
-----------------------------------------------------
00001 | Item 1 |3 |100 |12/07/2014 |
00001 | Item 2 |2 |50 |12/07/2014 |
00001 | Item 3 |1 |150 |12/07/2014 |
之后我想在我的表中看到这个
Transaction ID|Item Code |Total of Qty|Total of Price|Transaction Date|
-----------------------------------------------------------------------------------
00001 |Item 1, Item 2, Item 3| 6 | 150 | 12/07/2014 |
答案 0 :(得分:1)
使用GROUP_CONCAT
在GROUP BY中将字符串连接在一起:
SELECT TransactionID, GROUP_CONCAT(ItemCode) AS ItemCodes,
SUM(Qty) AS TotalofQty, SUM(Total) AS TotalPrice, TransactionDate
FROM TableA
GROUP BY TransactionID, TransactionDate;
编辑将RDBMS更改为SqlServer后,需要a hack来补偿SqlServer缺少像GROUP_CONCAT
这样的字符串折叠函数。这是STUFF / FOR XML PATH
一个:
SELECT a.[Transaction ID],
STUFF((
SELECT ',' + [Item Code]
FROM TableA
WHERE [Transaction ID] = a.[Transaction ID]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
AS ItemCodes,
SUM(Qty) AS TotalofQty, SUM(Total) AS TotalPrice, [Transaction Date]
FROM TableA a
GROUP BY a.[Transaction ID], a.[Transaction Date];
请注意,您需要手动将STUFF subquery
与相应的外部查询相关联。
答案 1 :(得分:1)
确实SQL Server中没有内置的concat函数,我怀疑会有这样的。原因是创建CLR User-Defined Aggregates非常容易。实际上,MSDN上已有这样的例子。您可以在此处找到创建GROUP_CONCAT
函数所需的所有内容 - String Utility Functions。
基本上,您需要按照以下步骤操作:
启用CLR
集成:
sp_configure 'clr enabled', 1
GO
RECONFIGURE
GO
创建以下C#类并构建.dll
:
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
Microsoft.SqlServer.Server.Format.UserDefined, //use clr serialization to serialize the intermediate result
IsInvariantToNulls = true,//optimizer property
IsInvariantToDuplicates = false,//optimizer property
IsInvariantToOrder = false,//optimizer property
MaxByteSize = 8000)] //maximum size in bytes of persisted value
public class Concatenate : Microsoft.SqlServer.Server.IBinarySerialize
{
/// <summary>
/// The variable that holds the intermediate result of the concatenation
/// </summary>
private StringBuilder intermediateResult;
/// <summary>
/// Initialize the internal data structures
/// </summary>
public void Init()
{
intermediateResult = new StringBuilder();
}
/// <summary>
/// Accumulate the next value, nop if the value is null
/// </summary>
/// <param name="value"></param>
public void Accumulate(SqlString value)
{
if (value.IsNull)
{
return;
}
intermediateResult.Append(value.Value).Append(',');
}
/// <summary>
/// Merge the partially computed aggregate with this aggregate.
/// </summary>
/// <param name="other"></param>
public void Merge(Concatenate other)
{
intermediateResult.Append(other.intermediateResult);
}
/// <summary>
/// Called at the end of aggregation, to return the results of the aggregation
/// </summary>
/// <returns></returns>
public SqlString Terminate()
{
string output = string.Empty;
//delete the trailing comma, if any
if (intermediateResult != null && intermediateResult.Length > 0)
output = intermediateResult.ToString(0, intermediateResult.Length - 1);
return new SqlString(output);
}
public void Read(BinaryReader r)
{
if (r == null) throw new ArgumentNullException("r");
intermediateResult = new StringBuilder(r.ReadString());
}
public void Write(BinaryWriter w)
{
if (w == null) throw new ArgumentNullException("w");
w.Write(intermediateResult.ToString());
}
}
部署程序集并创建函数:
DECLARE @SamplePath nvarchar(1024)
SET @SamplePath = 'C:\MySample\'
CREATE ASSEMBLY [StringUtils]
FROM @SamplePath + 'StringUtils.dll'
WITH permission_set = Safe;
GO
CREATE AGGREGATE [dbo].[Concatenate](@input nvarchar(4000))
RETURNS nvarchar(4000)
EXTERNAL NAME [StringUtils].[Concatenate];
GO
然后您可以将此函数用作任何标准聚合函数:
SELECT TransactionID, [dbo].Concatenate(ItemCode) AS ItemCodes,
SUM(Qty) AS TotalofQty, SUM(Total) AS TotalPrice, TransactionDate
FROM TableA
GROUP BY TransactionID, TransactionDate;
注意,我已经知道CLR
集成多年,但几个月前就开始使用它了。当您处理大量数据时,性能差异很大。