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

SQL Server中如何避免Foreach实现RxCui与Ndc的标签关联映射?

嘿,我明白你的痛点——不想用foreach挨个调用存储过程,又怕一次性传所有RxCui和Ndc会生成全量的无效关联。下面有两个靠谱的方案,帮你高效解决这个问题:

方案1:直接传入完整JSON到存储过程,SQL端解析处理

这种方法把整个DrugLabels对象序列成JSON直接传给存储过程,让SQL Server自己解析每个标签的RxCui和Ndc组,只建立同标签内的关联,完全不用C#端循环调用。

第一步:修改存储过程,支持JSON参数

CREATE PROCEDURE MapRxCuiToNdcByJson
    @drugLabelsJson NVARCHAR(MAX)
AS
BEGIN
    SET NOCOUNT ON;

    -- 解析JSON,拆分出每个标签下的RxCui和Ndc配对
    WITH LabelAssociations AS (
        SELECT 
            rxcui.value AS RxCuiCode,
            ndc.value AS NdcCode
        FROM 
            OPENJSON(@drugLabelsJson, '$.results') -- 遍历每个DrugLabel
            CROSS APPLY OPENJSON(JSON_VALUE([value], '$.openfda.rxcui')) AS rxcui -- 遍历当前标签的RxCui列表
            CROSS APPLY OPENJSON(JSON_VALUE([value], '$.openfda.product_ndc')) AS ndc -- 遍历当前标签的Ndc列表
    )
    -- 关联到已有的RxCui/Ndc表,插入关联(自动跳过已存在的配对)
    MERGE INTO [Common].[RxCuiNdc] T
    USING (
        SELECT 
            r.RxCuiId,
            n.NdcId
        FROM 
            LabelAssociations la
            INNER JOIN Common.RxCui r ON r.Code = la.RxCuiCode
            INNER JOIN Common.Ndc n ON n.Code = la.NdcCode
    ) S
    ON T.RxCuiId = S.RxCuiId AND T.NdcId = S.NdcId
    WHEN NOT MATCHED THEN 
        INSERT (RxCuiId, NdcId) 
        VALUES (S.RxCuiId, S.NdcId);
END

第二步:C#端调用,直接传序列化后的JSON

// 把整个DrugLabels对象序列化为JSON字符串
var json = JsonSerializer.Serialize(drugLabels);

// 调用存储过程(记得替换你的连接字符串)
using (var conn = new SqlConnection("YourDatabaseConnectionString"))
{
    await conn.OpenAsync();
    using (var cmd = new SqlCommand("MapRxCuiToNdcByJson", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add("@drugLabelsJson", SqlDbType.NVarChar, -1).Value = json;
        await cmd.ExecuteNonQueryAsync();
    }
}
方案2:用表值参数(TVP)批量传配对数据

如果你不想在SQL里处理JSON,可以在C#端先整理好所有需要关联的(RxCuiCode, NdcCode)配对,再用表值参数一次性传给存储过程——比传逗号分隔的字符串靠谱多了,不会因为代码里带逗号导致拆分错误。

第一步:创建SQL表值类型

CREATE TYPE RxCuiNdcPairType AS TABLE (
    RxCuiCode VARCHAR(256) NOT NULL,
    NdcCode VARCHAR(256) NOT NULL
);

第二步:修改存储过程接收表值参数

CREATE PROCEDURE MapRxCuiToNdcByTVP
    @rxCuiNdcPairs RxCuiNdcPairType READONLY
AS
BEGIN
    SET NOCOUNT ON;

    MERGE INTO [Common].[RxCuiNdc] T
    USING (
        SELECT 
            r.RxCuiId,
            n.NdcId
        FROM 
            @rxCuiNdcPairs lp
            INNER JOIN Common.RxCui r ON r.Code = lp.RxCuiCode
            INNER JOIN Common.Ndc n ON n.Code = lp.NdcCode
    ) S
    ON T.RxCuiId = S.RxCuiId AND T.NdcId = S.NdcId
    WHEN NOT MATCHED THEN 
        INSERT (RxCuiId, NdcId) 
        VALUES (S.RxCuiId, S.NdcId);
END

第三步:C#端准备数据并调用

// 准备存储配对的数据表
var pairTable = new DataTable();
pairTable.Columns.Add("RxCuiCode", typeof(string));
pairTable.Columns.Add("NdcCode", typeof(string));

// 遍历每个标签,把内部的RxCui和Ndc交叉添加到数据表
foreach (var label in drugLabels.results)
{
    foreach (var rxcui in label.openfda.rxcui)
    {
        foreach (var ndc in label.openfda.product_ndc)
        {
            pairTable.Rows.Add(rxcui, ndc);
        }
    }
}

// 调用存储过程
using (var conn = new SqlConnection("YourDatabaseConnectionString"))
{
    await conn.OpenAsync();
    using (var cmd = new SqlCommand("MapRxCuiToNdcByTVP", conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        // 配置表值参数
        var tvpParam = new SqlParameter("@rxCuiNdcPairs", SqlDbType.Structured)
        {
            TypeName = "RxCuiNdcPairType",
            Value = pairTable
        };
        cmd.Parameters.Add(tvpParam);
        await cmd.ExecuteNonQueryAsync();
    }
}
方案对比
  • 方案1:完全消除C#端的循环,一次数据库调用搞定,适合数据量较大的场景,SQL端处理逻辑更集中。
  • 方案2:C#端做数据整理,SQL端逻辑更简单,表值参数的方式比字符串拆分更稳定,不会出现特殊字符导致的错误。

两种方案都不会生成全量交叉的无效关联,只会建立每个标签内部RxCui和Ndc的对应关系,完美解决你的问题~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:36:28