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

SQL Server 2008兼容的JSON列提取与拆分优化方案问询

需求说明

我有存储员工数据的视图vwSupervisors,其中ActiveDepartments列存储JSON格式的多部门信息。需要编写SQL Server 2008兼容的查询,将每个员工按所属部门拆分为单独行,同时提取DepartmentId和DepartmentName作为列。

当前使用嵌套子查询结合CHARINDEX、SUBSTRING的实现方式过于繁琐,希望获得更简洁的替代方案,且不能使用SQL Server 2008不支持的JSON_VALUE、OPENJSON等函数。

员工数据示例

Usage,EmployeeID,EmailAddress,Name,LastName,FirstName,MiddleName,GlobalID,Birthdate,UsageTags,NameAliases,ActiveDepartments,ADPriority
SupervisorOfStudents,10039,DLname@schoolname.edu,Dr. Fname M. Lname,Lname,Fname,M,NULL,NULL,"[{""seqNo"":1,""Tag"":""Employee:Active""},{""seqNo"":2,""Tag"":""Employee:ActiveChair""},{""seqNo"":3,""Tag"":""Employee:ActiveFaculty""},{""seqNo"":4,""Tag"":""Employee:InActiveStaff""}]",[{""seqNo"":1,""Name"":""Lname,Fname M""}],"[{""DepartmentType"":""Employee"",""Departments"":[{""seqNo"":1,""DepartmentId"":""99901"",""DepartmentName"":""Chemistry""},{""seqNo"":2,""DepartmentId"":""99902"",""DepartmentName"":""School of Science""},{""seqNo"":3,""DepartmentId"":""99903"",""DepartmentName"":""Continuing Education""}]}]",1
SupervisorOfStudents,10079,FLname@schoolname.edu,Ms Fname M. Lname,Lname,Fname,M,NULL,NULL,"[{""seqNo"":1,""Tag"":""Employee:Active""},{""seqNo"":2,""Tag"":""Employee:ActiveManager""},{""seqNo"":3,""Tag"":""Employee:ActiveStaff""},{""seqNo"":4,""Tag"":""Student:Attended""}]",[{""seqNo"":1,""Name"":""Lname,Fname M""},{""seqNo"":2,""Name"":""Lname,Fname Middle""},{""seqNo"":3,""Name"":""Lname-laLastName,Lname Fname""}],"[{""DepartmentType"":""Employee"",""Departments"":[{""seqNo"":1,""DepartmentId"":""99801"",""DepartmentName"":""Athletics""}]}]",1

当前实现代码

SELECT
    Usage,
    EmployeeID,
    EmailAddress,
    Name,
    LastName,
    FirstName,
    MiddleName,
    GlobalID,
    Birthdate,
    UsageTags,
    NameAliases,
    DepartmentName,
    DepartmentId
FROM
    (
        SELECT
            Usage,
            EmployeeID,
            EmailAddress,
            Name,
            LastName,
            FirstName,
            MiddleName,
            GlobalID,
            Birthdate,
            UsageTags,
            NameAliases,
            CASE 
                WHEN CHARINDEX('"DepartmentName":"', ActiveDepartments) > 0 THEN
                    SUBSTRING(
                        ActiveDepartments, 
                        CHARINDEX('"DepartmentName":"', ActiveDepartments) + LEN('"DepartmentName":"'), 
                        CHARINDEX('"', ActiveDepartments, CHARINDEX('"DepartmentName":"', ActiveDepartments) + LEN('"DepartmentName":"')) - CHARINDEX('"DepartmentName":"', ActiveDepartments) - LEN('"DepartmentName":"')
                    )
                ELSE NULL
            END AS DepartmentName,
            CASE 
                WHEN CHARINDEX('"DepartmentId":"', ActiveDepartments) > 0 THEN
                    SUBSTRING(
                        ActiveDepartments, 
                        CHARINDEX('"DepartmentId":"', ActiveDepartments) + LEN('"DepartmentId":"'), 
                        CHARINDEX('"', ActiveDepartments, CHARINDEX('"DepartmentId":"', ActiveDepartments) + LEN('"DepartmentId":"')) - CHARINDEX('"DepartmentId":"', ActiveDepartments) - LEN('"DepartmentId":"')
                    )
                ELSE NULL
            END AS DepartmentId
        FROM
            vwSupervisors
    ) AS DepartmentInfo
WHERE
    Usage = 'SupervisorBasicInfo';
解决方案

针对SQL Server 2008的限制,可以借助数字辅助表结合字符串处理简化拆分逻辑,避免重复嵌套CHARINDEX的繁琐写法。

步骤1:创建数字辅助表

如果没有现成的数字表,可临时生成一个(这里生成1到100的数字,覆盖大部分部门数量场景):

WITH Numbers AS (
    SELECT TOP 100 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N
    FROM sys.all_columns
)
SELECT * FROM Numbers;

步骤2:简化拆分查询

利用数字表逐个定位每个部门的位置,提取对应的DepartmentId和DepartmentName:

WITH Numbers AS (
    SELECT TOP 100 ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS N
    FROM sys.all_columns
)
SELECT
    s.Usage,
    s.EmployeeID,
    s.EmailAddress,
    s.Name,
    s.LastName,
    s.FirstName,
    s.MiddleName,
    s.GlobalID,
    s.Birthdate,
    s.UsageTags,
    s.NameAliases,
    -- 提取DepartmentName
    SUBSTRING(
        s.ActiveDepartments,
        CHARINDEX('"DepartmentName":"', s.ActiveDepartments, n.N) + LEN('"DepartmentName":"'),
        CHARINDEX('"', s.ActiveDepartments, CHARINDEX('"DepartmentName":"', s.ActiveDepartments, n.N) + LEN('"DepartmentName":"')) 
        - (CHARINDEX('"DepartmentName":"', s.ActiveDepartments, n.N) + LEN('"DepartmentName":"'))
    ) AS DepartmentName,
    -- 提取DepartmentId
    SUBSTRING(
        s.ActiveDepartments,
        CHARINDEX('"DepartmentId":"', s.ActiveDepartments, n.N) + LEN('"DepartmentId":"'),
        CHARINDEX('"', s.ActiveDepartments, CHARINDEX('"DepartmentId":"', s.ActiveDepartments, n.N) + LEN('"DepartmentId":"')) 
        - (CHARINDEX('"DepartmentId":"', s.ActiveDepartments, n.N) + LEN('"DepartmentId":"'))
    ) AS DepartmentId
FROM vwSupervisors s
CROSS JOIN Numbers n
WHERE 
    s.Usage = 'SupervisorBasicInfo'
    -- 确保当前数字对应的部门存在
    AND CHARINDEX('"DepartmentId":"', s.ActiveDepartments, n.N) > 0
    -- 避免重复提取同一部门
    AND (n.N = 1 OR CHARINDEX('"DepartmentId":"', s.ActiveDepartments, n.N) > CHARINDEX('"DepartmentId":"', s.ActiveDepartments, n.N - 1));

方案优势

  • 消除嵌套子查询的冗余结构,逻辑更清晰
  • 利用数字表的循环特性,自动将多部门拆分为多行
  • 完全兼容SQL Server 2008,无需任何JSON专属函数

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 23:22:32