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

如何从竖线分隔CSV向表更新/插入数据?SQL Server 14版本受限

解决SQL Server 14版本无法使用STRING_SPLIT拆分分隔字符串的问题

我来帮你搞定这个需求——把临时表中用|分隔的部门拆分成多条记录,然后对Emp表执行更新/插入操作。既然你说SQL Server 14没法用STRING_SPLIT,我给你几个实用的替代方案,还有一个可能的小坑提醒:

先确认临时表结构(方便测试)

假设你的临时表是#TempEmp,先给出测试用的创建和插入语句:

CREATE TABLE #TempEmp (
    ID VARCHAR(20),
    DEPARTMENT VARCHAR(100),
    DESIGNATION VARCHAR(50),
    LOCATION VARCHAR(50),
    REGION VARCHAR(50),
    STATE VARCHAR(50)
);

INSERT INTO #TempEmp VALUES ('Test19768', 'Barclays|Citi Bank|Ireland', 'developer', NULL, NULL, NULL);

方法1:递归CTE拆分(最容易理解)

递归CTE会一步步把分隔字符串拆成单个部门,适合简单场景:

WITH SplitDepartments AS (
    -- 第一步:提取第一个部门,同时保留剩余未拆分的字符串
    SELECT 
        ID,
        DESIGNATION,
        LOCATION,
        REGION,
        STATE,
        LEFT(DEPARTMENT, CHARINDEX('|', DEPARTMENT + '|') - 1) AS SplitDept,
        STUFF(DEPARTMENT, 1, CHARINDEX('|', DEPARTMENT + '|'), '') AS RemainingDept
    FROM #TempEmp
    WHERE DEPARTMENT IS NOT NULL AND DEPARTMENT <> ''

    UNION ALL

    -- 递归:继续拆分剩余字符串,直到拆完
    SELECT 
        ID,
        DESIGNATION,
        LOCATION,
        REGION,
        STATE,
        LEFT(RemainingDept, CHARINDEX('|', RemainingDept + '|') - 1) AS SplitDept,
        STUFF(RemainingDept, 1, CHARINDEX('|', RemainingDept + '|'), '') AS RemainingDept
    FROM SplitDepartments
    WHERE RemainingDept IS NOT NULL AND RemainingDept <> ''
)
-- 用MERGE做UPSERT(匹配则更新,不匹配则插入)
MERGE INTO Emp AS Target
USING (
    SELECT 
        ID,
        SplitDept AS DEPARTMENT,
        DESIGNATION,
        LOCATION,
        REGION,
        STATE
    FROM SplitDepartments
) AS Source
ON Target.ID = Source.ID AND Target.DEPARTMENT = Source.DEPARTMENT
WHEN MATCHED THEN
    UPDATE SET 
        DESIGNATION = Source.DESIGNATION,
        LOCATION = Source.LOCATION,
        REGION = Source.REGION,
        STATE = Source.STATE
WHEN NOT MATCHED THEN
    INSERT (ID, DEPARTMENT, DESIGNATION, LOCATION, REGION, STATE)
    VALUES (Source.ID, Source.DEPARTMENT, Source.DESIGNATION, Source.LOCATION, Source.REGION, Source.STATE);

方法2:数字表拆分(性能更优)

如果要处理大量数据,用数字表拆分的性能会比递归CTE好。先临时生成一个数字表,再用它定位分隔符位置:

-- 临时生成一个包含1到1000的数字表(足够拆分大部分字符串)
SELECT TOP (1000) n = ROW_NUMBER() OVER (ORDER BY s1.object_id)
INTO #Numbers
FROM sys.all_objects s1 CROSS JOIN sys.all_objects s2;

-- 拆分字符串
WITH SplitDepartments AS (
    SELECT 
        te.ID,
        te.DESIGNATION,
        te.LOCATION,
        te.REGION,
        te.STATE,
        SplitDept = SUBSTRING(te.DEPARTMENT, n, CHARINDEX('|', te.DEPARTMENT + '|', n) - n)
    FROM #TempEmp te
    JOIN #Numbers n 
        ON n.n <= LEN(te.DEPARTMENT) + 1
        AND SUBSTRING('|' + te.DEPARTMENT, n, 1) = '|'
)
-- 同样执行MERGE操作
MERGE INTO Emp AS Target
USING (
    SELECT 
        ID,
        SplitDept AS DEPARTMENT,
        DESIGNATION,
        LOCATION,
        REGION,
        STATE
    FROM SplitDepartments
    WHERE SplitDept <> '' -- 过滤空值
) AS Source
ON Target.ID = Source.ID AND Target.DEPARTMENT = Source.DEPARTMENT
WHEN MATCHED THEN
    UPDATE SET 
        DESIGNATION = Source.DESIGNATION,
        LOCATION = Source.LOCATION,
        REGION = Source.REGION,
        STATE = Source.STATE
WHEN NOT MATCHED THEN
    INSERT (ID, DEPARTMENT, DESIGNATION, LOCATION, REGION, STATE)
    VALUES (Source.ID, Source.DEPARTMENT, Source.DESIGNATION, Source.LOCATION, Source.REGION, Source.STATE);

-- 用完临时数字表记得删掉
DROP TABLE #Numbers;

方法3:XML拆分(代码最简洁)

把分隔字符串转换成XML格式,再提取每个节点值,代码很紧凑:

WITH SplitDepartments AS (
    SELECT 
        te.ID,
        te.DESIGNATION,
        te.LOCATION,
        te.REGION,
        te.STATE,
        SplitDept = x.value('.', 'VARCHAR(100)')
    FROM #TempEmp te
    -- 把|替换成XML节点标签,转成XML类型
    CROSS APPLY (
        SELECT CAST('<d>' + REPLACE(te.DEPARTMENT, '|', '</d><d>') + '</d>' AS XML) AS DeptXML
    ) AS t
    -- 拆分每个XML节点
    CROSS APPLY t.DeptXML.nodes('/d') AS x(x)
)
-- MERGE操作同上
MERGE INTO Emp AS Target
USING (
    SELECT 
        ID,
        SplitDept AS DEPARTMENT,
        DESIGNATION,
        LOCATION,
        REGION,
        STATE
    FROM SplitDepartments
    WHERE SplitDept <> ''
) AS Source
ON Target.ID = Source.ID AND Target.DEPARTMENT = Source.DEPARTMENT
WHEN MATCHED THEN
    UPDATE SET 
        DESIGNATION = Source.DESIGNATION,
        LOCATION = Source.LOCATION,
        REGION = Source.REGION,
        STATE = Source.STATE
WHEN NOT MATCHED THEN
    INSERT (ID, DEPARTMENT, DESIGNATION, LOCATION, REGION, STATE)
    VALUES (Source.ID, Source.DEPARTMENT, Source.DESIGNATION, Source.LOCATION, Source.REGION, Source.STATE);

额外提醒:可能你其实能用STRING_SPLIT?

STRING_SPLIT是SQL Server 2016(版本13)及以后支持的,SQL Server 14(2017)本来应该支持。如果用不了,大概率是数据库兼容性级别设置太低。你可以检查一下:

SELECT name, compatibility_level FROM sys.databases WHERE name = '你的数据库名';

如果兼容性级别低于130,改成130或更高就能用STRING_SPLIT了:

ALTER DATABASE 你的数据库名 SET COMPATIBILITY_LEVEL = 130;

用STRING_SPLIT的话代码会更简单:

MERGE INTO Emp AS Target
USING (
    SELECT 
        te.ID,
        s.value AS DEPARTMENT,
        te.DESIGNATION,
        te.LOCATION,
        te.REGION,
        te.STATE
    FROM #TempEmp te
    CROSS APPLY STRING_SPLIT(te.DEPARTMENT, '|') s
    WHERE s.value <> ''
) AS Source
ON Target.ID = Source.ID AND Target.DEPARTMENT = Source.DEPARTMENT
WHEN MATCHED THEN
    UPDATE SET 
        DESIGNATION = Source.DESIGNATION,
        LOCATION = Source.LOCATION,
        REGION = Source.REGION,
        STATE = Source.STATE
WHEN NOT MATCHED THEN
    INSERT (ID, DEPARTMENT, DESIGNATION, LOCATION, REGION, STATE)
    VALUES (Source.ID, Source.DEPARTMENT, Source.DESIGNATION, Source.LOCATION, Source.REGION, Source.STATE);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 09:09:45