【问题标题】:Single select join Sql query单选连接Sql查询
【发布时间】:2013-04-24 08:59:49
【问题描述】:

使用TableA 和下面提供的数据,我需要一个SELECT 查询,它在TableB 中返回结果:

表A

Id  Cvs 
--------------------------------
1   aaa,eee,ccc,ggg,hhh,bbb
2   ggg,bbb,ccc,ggg,aaa,bbb,bbb
3   ddd,ggg,eee

表B

Id  Value
1   aaa
1   eee
1   ccc
1   ggg
1   hhh
1   bbb
2   ggg
2   bbb
2   ccc
2   ggg
2   aaa
2   bbb
2   bbb
3   ddd
3   ggg
3   eee

由于 T-SQL 函数或连接查询,请帮助我如何做到这一点。

【问题讨论】:

标签: sql sql-server tsql join


【解决方案1】:

请尝试:

DECLARE @table as TABLE(ID int, CVS  Nvarchar(50))
insert into @table
select 1, 'aaa,eee,ccc,ggg,hhh,bbb' CVS union all
select 2, 'ggg,bbb,ccc,ggg,aaa,bbb,bbb' CVS union all
select 3, 'ddd,ggg,eee'

;WITH Split_Col 
AS
(
    SELECT ID, CONVERT(XML,'<table><col>' + ColName + '</col></table>') AS xmlcol
    FROM
    (
        SELECT ID, Split.a.value('.', 'VARCHAR(100)') AS ColName  
        FROM  
        (
             SELECT ID, CAST ('<M>' + REPLACE(CVS, ',', '</M><M>') + '</M>' AS XML) AS ColName  
             FROM  (select * from @table) TableName
         ) AS A 
            CROSS APPLY ColName.nodes ('/M') AS Split(a)
    ) TableName
)

 SELECT      
 ID, xmlcol.value('/table[1]/col[1]','varchar(100)') AS studentID
 FROM Split_Col 
 order by ID

【讨论】:

    【解决方案2】:

    试试这个

    SELECT A.ID,  
         Split.a.value('.', 'VARCHAR(100)') AS CVS  
    FROM  
    (
        SELECT ID,  
             CAST ('<M>' + REPLACE(CVS, ',', '</M><M>') + '</M>' AS XML) AS CVS  
        FROM  TableA 
    ) AS A CROSS APPLY CVS.nodes ('/M') AS Split(a)
    

    【讨论】:

      【解决方案3】:

      我将创建一个单独的函数,从 CSV 列表中返回所有值(包括重复值):

      IF  EXISTS (SELECT * FROM sysobjects WHERE id  = OBJECT_ID(N'[dbo].[fn_TEST]') AND xtype  IN (N'FN', N'IF', N'TF'))
      BEGIN
          DROP FUNCTION [dbo].[fn_TEST]
      END
      GO
      
      SET ANSI_NULLS ON
      GO
      
      SET QUOTED_IDENTIFIER ON
      GO
      
      CREATE FUNCTION [dbo].[fn_TEST]
      (
          @CSVList NVARCHAR(MAX)
      )
      RETURNS @ResultSet TABLE
      (
           RecValue NVARCHAR(MAX)
          ,RecID BIGINT IDENTITY(1, 1) PRIMARY KEY
      )
      AS
      BEGIN
      
          DECLARE @XML xml = N'<r><![CDATA[' + REPLACE(@CSVList, ',', ']]></r><r><![CDATA[') + ']]></r>'
      
          INSERT INTO @ResultSet (RecValue)
          SELECT RTRIM(LTRIM(Tbl.Col.value('.', 'nvarchar(max)')))
          FROM @xml.nodes('//r') Tbl(Col)
      
          RETURN
      END
      
      GO
      

      然后您可以像这样简单地使用“SELECT”语句和“CROSS APPLY”语句:

      SET NOCOUNT ON
      GO
      
          DECLARE @DataSource AS TABLE
          (
               ID TINYINT IDENTITY(1,1)
              ,CSV NVARCHAR(4000)
          )
      
          INSERT INTO @DataSource ([CSV])
          VALUES ('aaa,eee,ccc,ggg,hhh,bbb')
                ,('ggg,bbb,ccc,ggg,aaa,bbb,bbb')
                ,('ddd,ggg,eee')
      
          SELECT ID
                ,RecValue
          FROM @DataSource DS
          CROSS APPLY [dbo].[fn_TEST](CSV) FN
      
      SET NOCOUNT OFF
      GO
      

      【讨论】:

        【解决方案4】:

        请尝试其中一种 -

        DECLARE @temp TABLE
        (
              id INT
            , string NVARCHAR(200)
        )
        
        DECLARE @Separator CHAR(1)
        SELECT @Separator = ','
        
        INSERT INTO @temp (id, string)
        VALUES 
        (1,   'aaa,eee,ccc,ggg,hhh,bbb'),
        (2,   'ggg,bbb,ccc,ggg,aaa,bbb,bbb'),
        (3,   'ddd,ggg,eee')
        

        1. XML

        SELECT 
              id = p.value('(./n)[1]', 'INT')
            , name = p.value('(./s)[1]', 'NVARCHAR(200)')
        FROM (
            SELECT field = CAST('<r><s>' + REPLACE(SUBSTRING(',' + t.string + ',', 2, LEN(',' + t.string + ',')), @Separator, '</s><n>' + CAST(t.id AS VARCHAR(10)) + '</n></r><r><s>') + '</s></r>' AS XML) 
            FROM @temp t
        ) d
        CROSS APPLY field.nodes('/r') t(p)
        WHERE t.p.exist('n') = 1
        

        2。 spt_values

        SELECT 
              t.id
            , name = 
                SUBSTRING(
                      ',' + t.string + ','
                    , number + 1
                    , CHARINDEX(@Separator, ',' + t.string + ',', number + 1) - number - 1)
        FROM @temp t
        CROSS JOIN [master].dbo.spt_values n
        WHERE [type] = 'p'
            AND number <= LEN(',' + t.string + ',') - 1
            AND SUBSTRING(',' + t.string + ',', number, 1) = @Separator
        

        3.同时

        DECLARE @items TABLE 
        (
              id INT
            , name NVARCHAR(50)
        )
        
        DECLARE
              @id INT
            , @string NVARCHAR(2000)
            , @pos INT
        
        DECLARE cur CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
            SELECT id, string
            FROM @temp
        
        OPEN cur
        
        FETCH NEXT FROM cur INTO @id, @string
        
        WHILE @@FETCH_STATUS = 0 BEGIN
        
            WHILE LEN(@string) > 0 BEGIN
        
                SELECT @pos = CHARINDEX(@Separator, @string, 1)
        
                IF @pos = 0
                    SELECT @pos = LEN(@string)
        
                INSERT INTO @items (id, name) 
                SELECT @id, SUBSTRING(@string, 1, @pos - 1)
        
                SELECT @string = SUBSTRING(@string, @pos + 1, LEN(@string) - @pos)
        
            END
        
            FETCH NEXT FROM cur INTO @id, @string
        
        END
        
        CLOSE cur
        DEALLOCATE cur
        
        SELECT  
              i.id
            , i.name 
        FROM @items i
        WHERE name != ''
        

        4. CTE

        ;WITH a AS
        (
            SELECT 
                  id
                , start_pos = 1
                , end_pos = CHARINDEX(@Separator, t.string)
                , t.string
            FROM @temp t
        
            UNION ALL
        
            SELECT 
                  id
                , end_pos + 1
                , CHARINDEX(@Separator, string, end_pos + 1)
                , string
            FROM a
            WHERE end_pos > 0
        )
        
        SELECT 
              d.id
            , d.name 
        FROM (
            SELECT 
                  a.id
                , name = SUBSTRING(
                      string
                    , start_pos
                    , ABS(end_pos - start_pos)
                ) 
            FROM a
        ) d
        WHERE d.name != ''
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多