【问题标题】:multi value in same record sql同一记录sql中的多个值
【发布时间】:2018-12-23 12:05:21
【问题描述】:

我有 4 张桌子:

  1. 主表Applications,示例数据如下:

    Id | Craft_Name | Area     | PPE       | Potential
    ---+------------+----------+-----------+-------------
     1 | anas       | 1, 2, 3, | 4, 1, 3,  | 4, 2, 
    
  2. 第二桌Area

    Id | Area
    ---+----------
     1 | Jordan
     2 | USA
     3 | China
    
  3. 第三张桌子PPE

    Id | PPE 
    ---+-----------------
     1 | Safety Shoes   
     2 | Safety Gloves  
     3 | Electrical Gloves
     4 | Thermal Gloves 
    
  4. 第四桌Potential

    ID | Potential
    ---+----------------------
     1 | Working at Height
     2 | Falling Objects
     3 | Sharp Edges
     4 | Inhalation
    

最后我需要SQL查询的结果如下:

Id | Craft_Name | Area                | PPE                                                   | Potential
---+------------+---------------------+-------------------------------------------------------+-----------------------------
 1 | anas       | Jordan, USA, China, | Thermal Gloves, Working at Height, Electrical Gloves, | Inhalation, Falling Objects, 

【问题讨论】:

  • 你的 dbms 是什么?
  • 修改你的设计,不要使用这样的列表。那只会让事情变得复杂。使用链接表。
  • 嗨。这是一个常见问题解答。请始终使用 Google 错误消息和许多清晰、简洁和特定的版本/措辞,使用和不使用您的特定字符串/名称和“site:stackoverflow.com”和标签,并阅读许多答案。将您发现的相关关键字添加到搜索中。如果您没有找到答案,请发布,使用 1 个变体搜索作为标签的标题和关键字。如果您确实有要发布的非重复代码问题,请阅读并在minimal reproducible example 上采取行动。 PSIs storing a delimited list in a database column really that bad?

标签: sql join multivalue


【解决方案1】:

您可以通过两种方式做到这一点。

  1. 更改您的应用程序表结构以包含新的 3 个多对多关系表。 (推荐,它更容易在分析中进行任何类型)
  2. 或者你可以使用下面这样复杂的代码,并在其中组合了许多复杂的查询。

    IF OBJECT_ID('tempdb..#AreaTable') IS NOT NULL
        DROP TABLE #AreaTable
    IF OBJECT_ID('tempdb..#PPETable') IS NOT NULL
        DROP TABLE #PPETable
    
    ; WITH AreaTable AS (
        SELECT 
            A.ID, A.CreaftName, AreaName
        FROM  
            (
                SELECT T1.ID, T1.CreaftName,T1.[AreaIDs],T2.my_Splits
                FROM
                    (
                        SELECT *,
                            CAST('<X>'+replace([AreaIDs],',','</X><X>')+'</X>' as XML) as my_Xml 
                        FROM [dbo].[Applications]) T1
                        CROSS APPLY
                        (
                            SELECT 
                                my_Data.D.value('.','varchar(50)') as my_Splits
                            FROM 
                                T1.my_Xml.nodes('X') as my_Data(D)
                        ) T2
                    ) A 
        INNER JOIN [dbo].[Areas] B on A.my_splits = B.ID
    )
    
    --SELECT * FROM TempTable
    
    SELECT DISTINCT ST2.ID, St2.CreaftName,
        SUBSTRING(
            (
                SELECT ','+ ST1.AreaName  AS [text()]
                FROM AreaTable ST1
                WHERE ST1.ID = ST2.ID
                ORDER BY ST1.ID
                FOR XML PATH ('')
            ), 2, 1000) [Areas]
    INTO #AreaTable
    FROM [dbo].[Applications] ST2
    
    ;WITH PPETable AS (
        SELECT 
            A.ID, A.CreaftName, PPEName
        FROM  
            (
                SELECT T1.ID, T1.CreaftName,T1.PPEIDs,T2.my_Splits
                FROM
                    (
                        SELECT *,
                            CAST('<X>'+replace(PPEIDs,',','</X><X>')+'</X>' as XML) as my_Xml 
                        FROM [dbo].[Applications]) T1
                        CROSS APPLY
                        (
                            SELECT 
                                my_Data.D.value('.','varchar(50)') as my_Splits
                            FROM 
                                T1.my_Xml.nodes('X') as my_Data(D)
                        ) T2
                    ) A 
        INNER JOIN [dbo].[PPE] B on A.my_splits = B.ID
    )
    
    --SELECT * FROM TempTable
    
    SELECT DISTINCT ST2.ID, St2.CreaftName,
        SUBSTRING(
            (
                SELECT ','+ ST1.PPEName  AS [text()]
                FROM PPETable ST1
                WHERE ST1.ID = ST2.ID
                ORDER BY ST1.ID
                FOR XML PATH ('')
            ), 2, 1000) [PPEs]
    INTO #PPETable
    FROM [dbo].[Applications] ST2
    
    SELECT MainTable.ID, MainTable.CreaftName, A.Areas, B.[PPEs]
    FROM 
        [dbo].[Applications] AS MainTable
        LEFT OUTER JOIN #AreaTable AS A ON MainTable.ID = A.ID
        LEFT OUTER JOIN #PPETable AS B ON MainTable.ID = B.ID
    
    
    IF OBJECT_ID('tempdb..#AreaTable') IS NOT NULL
        DROP TABLE #AreaTable
    IF OBJECT_ID('tempdb..#PPETable') IS NOT NULL
        DROP TABLE #PPETable
    

您可以使用以下代码生成我创建此脚本时使用的表格供您参考

    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PPE]') AND type in (N'U'))
    DROP TABLE [dbo].[PPE]
    GO
    /****** Object:  Table [dbo].[Areas]    Script Date: 23/12/2018 10:43:40 AM ******/
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Areas]') AND type in (N'U'))
    DROP TABLE [dbo].[Areas]
    GO
    /****** Object:  Table [dbo].[Applications]    Script Date: 23/12/2018 10:43:40 AM ******/
    IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Applications]') AND type in (N'U'))
    DROP TABLE [dbo].[Applications]
    GO
    /****** Object:  Table [dbo].[Applications]    Script Date: 23/12/2018 10:43:40 AM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Applications]') AND type in (N'U'))
    BEGIN
    CREATE TABLE [dbo].[Applications](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [CreaftName] [nvarchar](50) NULL,
        [AreaIDs] [nvarchar](50) NULL,
        [PPEIDs] [nvarchar](50) NULL,
        CONSTRAINT [PK_Applications] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    END
    GO
    /****** Object:  Table [dbo].[Areas]    Script Date: 23/12/2018 10:43:40 AM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Areas]') AND type in (N'U'))
    BEGIN
    CREATE TABLE [dbo].[Areas](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [AreaName] [nvarchar](50) NULL,
        CONSTRAINT [PK_Ares] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    END
    GO
    /****** Object:  Table [dbo].[PPE]    Script Date: 23/12/2018 10:43:40 AM ******/
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[PPE]') AND type in (N'U'))
    BEGIN
    CREATE TABLE [dbo].[PPE](
        [ID] [int] IDENTITY(1,1) NOT NULL,
        [PPEName] [nvarchar](50) NULL,
        CONSTRAINT [PK_PPE] PRIMARY KEY CLUSTERED 
    (
        [ID] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    END
    GO
    SET IDENTITY_INSERT [dbo].[Applications] ON 

    INSERT [dbo].[Applications] ([ID], [CreaftName], [AreaIDs], [PPEIDs]) VALUES (1, N'Anas', N'1,3,2,', N'1,3')
    INSERT [dbo].[Applications] ([ID], [CreaftName], [AreaIDs], [PPEIDs]) VALUES (2, N'Islam', N',6,5,3', N'2')
    INSERT [dbo].[Applications] ([ID], [CreaftName], [AreaIDs], [PPEIDs]) VALUES (3, N'Mohammad', N'4', NULL)
    SET IDENTITY_INSERT [dbo].[Applications] OFF
    SET IDENTITY_INSERT [dbo].[Areas] ON 

    INSERT [dbo].[Areas] ([ID], [AreaName]) VALUES (1, N'Jordan')
    INSERT [dbo].[Areas] ([ID], [AreaName]) VALUES (2, N'China')
    INSERT [dbo].[Areas] ([ID], [AreaName]) VALUES (3, N'USA')
    INSERT [dbo].[Areas] ([ID], [AreaName]) VALUES (4, N'Colombia')
    INSERT [dbo].[Areas] ([ID], [AreaName]) VALUES (5, N'Costa Rica')
    INSERT [dbo].[Areas] ([ID], [AreaName]) VALUES (6, N'Panama')
    SET IDENTITY_INSERT [dbo].[Areas] OFF
    SET IDENTITY_INSERT [dbo].[PPE] ON 

    INSERT [dbo].[PPE] ([ID], [PPEName]) VALUES (1, N'Safety Shoes')
    INSERT [dbo].[PPE] ([ID], [PPEName]) VALUES (2, N'Safety Gloves')
    INSERT [dbo].[PPE] ([ID], [PPEName]) VALUES (3, N'Electrical Gloves')
    SET IDENTITY_INSERT [dbo].[PPE] OFF

【讨论】:

    【解决方案2】:

    例如 - 面积表(继续其他表)

    select 
        (select Area.Area + ',' 
         from dbo.Area 
         where charindex(',' + cast(Area.Id as varchar(10)) + ',', ',' + isnull(Applications.Area, '') + ',') > 0 
         for xml path('')) 
    from 
        dbo.Applications
    

    【讨论】:

    • 对。继续到其他领域
    猜你喜欢
    • 2012-09-04
    • 2013-04-14
    • 1970-01-01
    • 2020-12-22
    • 1970-01-01
    • 1970-01-01
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多