【问题标题】:How to Insert Multiple Row from one Column [closed]如何从一列插入多行[关闭]
【发布时间】:2014-12-07 07:36:36
【问题描述】:

我想在一列中插入多行。

对于我这样的 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     |

【问题讨论】:

  • 在单个单元格中有多个值显然违反了数据库设计的第一范式。强烈建议不要这样做!
  • 我认为Total of Price 应该是300,而不是150,对吗?
  • 不想想要存储它。如果您希望它作为查询的结果,那么它是一个非常标准的pivot 查询。

标签: c# sql sql-server


【解决方案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;

SqlFiddle here

编辑 将 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 与相应的外部查询相关联。

SqlServer Fiddle

【讨论】:

  • 谢谢!但 GROUP_CONCAT 在 Sql Server 2008 中无法识别。
  • 那么你为什么要用mysql标记你的问题呢? SqlServer 中有几个技巧可以折叠字符串,AFAIK STUFF / FOR XML PATHstill the best
  • 对不起,我觉得这对我来说有点熟悉..
  • 我已更新并更改了您问题的标记。另外,欢迎使用 StackOverflow - 下次还请附上您尝试解决问题的示例:)
【解决方案2】:

在 SQL Server 中确实没有内置的 concat 函数,我怀疑会有这样的函数。原因是创建CLR User-Defined Aggregates 非常容易。实际上,MSDN 上已经有这样的例子。您可以在这里找到创建 GROUP_CONCAT 函数所需的一切 - String Utility Functions

基本上,您需要按照以下步骤操作:

  1. 启用CLR 集成:

    sp_configure 'clr enabled', 1
    GO
    RECONFIGURE
    GO
    
  2. 创建以下 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());
        }
    }
    
  3. 部署程序集并创建您的函数:

    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 集成多年,但几个月前开始使用它。当您处理大量数据时,性能差异是巨大的。

【讨论】:

    猜你喜欢
    • 2012-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-13
    • 1970-01-01
    相关资源
    最近更新 更多