You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将首查询ItemId存为标量变量传入第二个查询匹配生成数据表

问题根因

你的现有代码存在3个核心问题:

  • 仅传入了单个@ItemID参数查询修改时间,没有遍历第一个查询返回的所有ItemID,所以只能拿到单条记录的修改时间
  • DataTable.Merge() 是行追加逻辑而非按主键关联合并列,调用后只会把第二个表的行追加到第一个表末尾,不会将修改时间拼到对应ItemID的同一行
  • 末尾多余的adapter.Fill(dt)会触发二次查询,覆盖之前的合并结果
最优方案:SQL层面直接关联查询

直接把两个查询的逻辑合并为一次SQL查询,不需要在内存做二次关联,性能更高、逻辑更简单:

private const string MergedItemsQuery = @"
WITH History AS (
    SELECT id.ItemID, ih.ActionedDate
    , ROW_NUMBER() OVER(PARTITION BY id.ItemID ORDER BY ih.ActionedDate DESC) AS vn
    FROM AgilityItemView v
    JOIN ItemDetail id
        ON id.ItemDetailID = v.ItemDetailId
    JOIN ItemHistory ih
        ON ih.ItemDetailID = id.ItemDetailID 
    WHERE id.[Status] in ('Released', 'Withdrawn')
    AND V.VersionRank = 1 AND V.[Type] = 'Document'
    AND ih.Action in (
      'Create','Edit','ItemCreatedByChanged'
    , 'ItemCustomPropertiesChanged','ItemNumberChanged','ItemRoleChanged'
    , 'ItemTitleChanged','Release','Restore'
    , 'ReturnToDraft','Revise','Withdraw'
    )
)
SELECT 
  id.ItemId, id.ItemDetailID, id.Status, id.Number
, id.Title, id.CreatedDate, id.WithdrawnDate
, RevisionNumber = id.MajorRevisionNumber + ISNULL(id.RevisionNumberOffset, 0)
, LastModifiedDate = h.ActionedDate
FROM AgilityItemView v
JOIN ItemDetail id
    ON id.ItemDetailID = v.ItemDetailId
LEFT JOIN History h
    ON h.ItemID = id.ItemID AND h.vn = 1
WHERE id.[Status] in ('Released', 'Withdrawn')
AND V.VersionRank = 1 AND V.[Type] = 'Document'";

直接执行这个查询就能拿到包含LastModifiedDate的完整结果,不需要后续内存关联。

备选方案:C#内存层面关联(适合后续需拼接多来源数据的场景)

如果你后续要从多个不同查询/接口拿字段拼接,按以下步骤实现:

  1. 先查询所有Item基础数据,收集所有ItemID
  2. 批量查询所有ItemID对应的LastModifiedDate,存入字典做匹配
  3. 遍历基础数据,将LastModifiedDate赋值到对应行
private DataTable GetData(string itemsQuery, string modifiedDataQuery)
{
    using var connection = new SqlConnection(_connectionString);
    connection.Open();

    // 第一步:查所有基础Item数据
    using var itemCmd = new SqlCommand(itemsQuery, connection);
    var itemAdapter = new SqlDataAdapter(itemCmd);
    var itemDt = new DataTable();
    itemAdapter.Fill(itemDt);
    // 给基础表加LastModifiedDate列
    itemDt.Columns.Add("LastModifiedDate", typeof(DateTime));

    // 第二步:收集所有ItemId,批量查修改时间
    var itemIds = itemDt.AsEnumerable().Select(r => r.Field<Guid>("ItemId")).Distinct().ToList();
    // 构建IN参数,避免SQL注入
    var paramList = new List<SqlParameter>();
    var paramPlaceholders = new List<string>();
    for (int i = 0; i < itemIds.Count; i++)
    {
        var paramName = $"@ItemId{i}";
        paramPlaceholders.Add(paramName);
        paramList.Add(new SqlParameter(paramName, itemIds[i]));
    }
    // 修改第二个查询的条件为IN
    var batchModifiedQuery = modifiedDataQuery.Replace("AND ItemId = @ItemID", $"AND ItemId IN ({string.Join(",", paramPlaceholders)})");
    using var modifiedCmd = new SqlCommand(batchModifiedQuery, connection);
    modifiedCmd.Parameters.AddRange(paramList.ToArray());
    var modifiedAdapter = new SqlDataAdapter(modifiedCmd);
    var modifiedDt = new DataTable();
    modifiedAdapter.Fill(modifiedDt);

    // 第三步:把修改时间转成字典,匹配赋值
    var modifiedDict = modifiedDt.AsEnumerable()
        .ToDictionary(r => r.Field<Guid>("ItemId"), r => r.Field<DateTime>("LastModifiedDate"));
    foreach (DataRow row in itemDt.Rows)
    {
        var itemId = row.Field<Guid>("ItemId");
        if (modifiedDict.TryGetValue(itemId, out var lastModified))
        {
            row["LastModifiedDate"] = lastModified;
        }
    }

    return itemDt;
}
注意事项
  • 批量查询如果ItemId数量超过2000,建议分批查询避免SQL参数上限
  • 后续补充其他字段时,都可以用字典匹配的方式往基础DataTable里加列赋值,最后直接用这个表导出CSV即可

内容的提问来源于stack exchange,提问作者lross15

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 01:45:04