在列中显示n个电话号码

时间:2016-02-12 18:04:17

标签: sql-server tsql

Hello T-SQL社区

我有一个项目,我需要在星期一结束时交付。因为我已经用尽所有其他形式的研究,我迫切需要你的帮助!

我想做的是如下

返回将表1转换为表2的数据集

表1:

def parse(self, response):
    for sel in response.xpath('//table[@class]/tbody/tr'):
        item = SET()
        item['title'] = sel.xpath('td[1]/a[contains(@href,"ssoPageId")]/text()').extract()
        item['open'] = sel.xpath('td[3]/text()').extract()
        item['hi'] = sel.xpath('td[4]/text()').extract()
        item['lo'] = sel.xpath('td[5]/text()').extract()
        item['last'] = sel.xpath('td[6]/text()').extract()
        item['bid'] = sel.xpath('td[9]/text()').extract()
        item['ask'] = sel.xpath('td[10]/text()').extract()
        item['vol'] = sel.xpath('td[11]/text()').extract()
        urll = response.xpath('//table[@class]/tbody/tr/td[1]/a[contains(@href,"ssoPageId")]/@href').extract()
        urls = ["http://marketdata.set.or.th/mkt/" + i for i in urll]
        for url in urls:
            yield scrapy.Request(url,
                                 callback=self.parse_following_urls,
                                 meta={'item': item})

对此...

表2:

Customer_No Name Telephone_No Address   Street_Name Postcode
=========== ==== ============ ========= =========== ========
635532      Mr X 0771111111   FLAT 1000 BEACH ROAD  BN23 5HT
635532      Mr X 0771112222   FLAT 1000 BEACH ROAD  BN23 5HT
635532      Mr X 01903773333  FLAT 1000 BEACH ROAD  BN23 5HT
635532      Mr X 01903774444  FLAT 1000 BEACH ROAD  BN23 5HT

每位客户最多可以有10个电话号码。

为清楚起见,上图显示在附图中

这是我目前建立的查询,但它受到我硬编码的电话字段数量的限制。我希望动态构建列

Customer_No Name Telephone_No_1 Telephone_No_2 Telephone_No_3 Telephone_No_4 Address   Street_Name Postcode
=========== ==== ============== ============== ============== ============== ========= =========== ======== 
635532      Mr X 0771111111     0771112222     01903773333    01903774444    FLAT 1000 BEACH ROAD  BN23 5HT

我将非常感谢你对此的帮助。

非常感谢!

Example as picture

4 个答案:

答案 0 :(得分:4)

假设您正在使用SQL-Server 2012及更高版本

创建样本数据:

CREATE TABLE #temp (Customer_No INT, Name  VARCHAR(100),  Telephone_No VARCHAR(100),   Address VARCHAR(100), Street_Name VARCHAR(100), Postcode VARCHAR(100))

INSERT INTO #temp
VALUES
(635532,'Mr X','0771111111','FLAT 1000','BEACH ROAD','BN23 5HT'),          
(635532,'Mr X','0771112222','FLAT 1000','BEACH ROAD','BN23 5HT'),       
(635532,'Mr X','01903773333','FLAT 1000','BEACH ROAD','BN23 5HT'),     
(635532,'Mr X','01903774444' ,'FLAT 1000','BEACH ROAD','BN23 5HT')

使用带有CASE语句和窗口函数的CTE查询将电话号码放在正确的标题下:

;WITH CTE AS (
    SELECT  #temp.Customer_No, 
          #temp.Name,  
          CASE WHEN Row_number()OVER(partition BY Customer_No ORDER BY Telephone_No) = 1 THEN  #temp.Telephone_No END  AS Telephone_No_1, 
          CASE WHEN Row_number()OVER(partition BY Customer_No ORDER BY Telephone_No) = 2 THEN  #temp.Telephone_No END  AS Telephone_No_2, 
          CASE WHEN Row_number()OVER(partition BY Customer_No ORDER BY Telephone_No) = 3 THEN  #temp.Telephone_No END  AS Telephone_No_3, 
          CASE WHEN Row_number()OVER(partition BY Customer_No ORDER BY Telephone_No) = 4 THEN  #temp.Telephone_No END  AS Telephone_No_4, 
          #temp.Address, 
          #temp.Street_Name, 
          #temp.Postcode 
    FROM #temp)

 SELECT  CTE.Customer_No, 
       CTE.Name, 
       MAX(CTE.Telephone_No_1) Telephone_No_1, 
       MAX(CTE.Telephone_No_2) Telephone_No_2, 
       MAX(CTE.Telephone_No_3) Telephone_No_3, 
       MAX(CTE.Telephone_No_4) Telephone_No_4, 
       CTE.Address, 
       CTE.Street_Name, 
       CTE.Postcode
FROM CTE
GROUP BY      CTE.Customer_No, 
          CTE.Name, 
          CTE.Address,
          CTE.Street_Name,
          CTE.Postcode;

结果:

enter image description here

以下是上述动态版本,因此您无需担心电话号码的数量:

创建样本数据

IF OBJECT_ID('tempdb..#TEMP') IS NOT NULL
    DROP TABLE #TEMP; 
CREATE TABLE #temp (Customer_No INT, Name  VARCHAR(100),  Telephone_No VARCHAR(100),   Address VARCHAR(100), Street_Name VARCHAR(100), Postcode VARCHAR(100))

INSERT INTO #temp
VALUES
(635532,'Mr X','0771111111','FLAT 1000','BEACH ROAD','BN23 5HT'),          
(635532,'Mr X','0771112222','FLAT 1000','BEACH ROAD','BN23 5HT'),       
(635532,'Mr X','01903773333','FLAT 1000','BEACH ROAD','BN23 5HT'),     
(635532,'Mr X','01903774444' ,'FLAT 1000','BEACH ROAD','BN23 5HT')

解决方案的动态部分,它将生成类似于上述查询的查询:

IF OBJECT_ID('tempdb..#TEMP2') IS NOT NULL
    DROP TABLE #TEMP2; 

    SELECT  #temp.Customer_No, 
          #temp.Name,  
          Row_number()OVER(partition BY Customer_No ORDER BY Telephone_No) AS rn, 
          #temp.Telephone_No, 
          #temp.Address, 
          #temp.Street_Name, 
          #temp.Postcode INTO #temp2
    FROM #temp


DECLARE @SQL1 VARCHAR(max) ='';

SELECT @SQL1 = '
;WITH CTE AS (
    SELECT  #TEMP2.Customer_No, 
          #TEMP2.Name, ' 

SELECT  @SQL1+='CASE WHEN rn ='+CAST(rn AS VARCHAR)+'THEN  #TEMP2.Telephone_No END  AS Telephone_No_'+CAST(rn AS VARCHAR)+',' FROM #temp2

SELECT @SQL1+= '#TEMP2.Address, 
          #TEMP2.Street_Name, 
          #TEMP2.Postcode 
    FROM #TEMP2)

 SELECT  CTE.Customer_No, 
       CTE.Name,'

SELECT @SQL1+='MAX(CTE.Telephone_No_'+CAST(rn AS VARCHAR)+') AS Telephone_No_'+CAST(rn AS VARCHAR)+','FROM #temp2

SELECT @SQL1+='CTE.Address, 
       CTE.Street_Name, 
       CTE.Postcode
FROM CTE
GROUP BY      CTE.Customer_No, 
          CTE.Name, 
          CTE.Address,
          CTE.Street_Name,
          CTE.Postcode;'



 PRINT(@SQL1)

 EXECUTE (@SQL1)

打印声明的结果:

enter image description here

整个查询的结果:

enter image description here

答案 1 :(得分:0)

我不认为这是一个直接的支点。这是一个工作示例

CREATE TABLE #test
  (
     Customer_No  INT,
     NAME         VARCHAR(50),
     Telephone_No NUMERIC(15),
     Address      VARCHAR(50),
     Street_Name  VARCHAR(50),
     Postcode     VARCHAR(50)
  ) 

insert #test values
(635532 ,'Mr X' ,   0771111111  ,'FLAT 1000' ,  'BEACH ROAD' , 'BN23 5HT'),
(635532 ,'Mr X' ,   0771112222  ,'FLAT 1000' ,  'BEACH ROAD' , 'BN23 5HT'),
(635532 ,'Mr X' ,   01903773333 ,'FLAT 1000' ,  'BEACH ROAD' , 'BN23 5HT'),
(635532 ,'Mr X' ,   01903774444 ,'FLAT 1000' ,  'BEACH ROAD' , 'BN23 5HT'),
(635533 ,'Mr X' ,   01903774444 ,'FLAT 1000' ,  'BEACH ROAD' , 'BN23 5HT')

DECLARE @sql  NVARCHAR(max),
        @cnt  INT,
        @incr INT = 1

SELECT @cnt = (SELECT TOP 1 Count(1) AS cnt
               FROM   #test
               GROUP  BY Customer_No
               ORDER  BY cnt DESC) --To get the max phone number count 

SET @sql = '
;with cte as
(
SELECT Row_number()OVER(partition BY Customer_No ORDER BY Telephone_No) as t_list, 
       *
FROM   #test 
)
select Customer_No,Name,'

WHILE @incr <= @cnt -- used just to frame the query 
  BEGIN
      SET @sql += 'max(case when t_list = '+ Cast(@incr AS VARCHAR(15))+ ' then Telephone_No end) as Telephone_No'
                  + Cast(@incr AS VARCHAR(15)) + ','
      SET @incr+=1
  END

SET @sql+= 'Address ,Street_Name ,Postcode from cte group by Customer_No,Name,Address ,Street_Name ,Postcode'

--PRINT @sql

EXEC Sp_executesql @sql 

<强>结果:

╔═════════════╦══════╦════════════════╦════════════════╦════════════════╦════════════════╦═══════════╦═════════════╦══════════╗
║ Customer_No ║ Name ║ Telephone_No_1 ║ Telephone_No_2 ║ Telephone_No_3 ║ Telephone_No_4 ║  Address  ║ Street_Name ║ Postcode ║
╠═════════════╬══════╬════════════════╬════════════════╬════════════════╬════════════════╬═══════════╬═════════════╬══════════╣
║      635532 ║ Mr X ║      771111111 ║ 771112222      ║ 1903773333     ║ 1903774444     ║ FLAT 1000 ║ BEACH ROAD  ║ BN23 5HT ║
║      635533 ║ Mr X ║     1903774444 ║ NULL           ║ NULL           ║ NULL           ║ FLAT 1000 ║ BEACH ROAD  ║ BN23 5HT ║
╚═════════════╩══════╩════════════════╩════════════════╩════════════════╩════════════════╩═══════════╩═════════════╩══════════╝

答案 2 :(得分:0)

首先,我赞赏你纠正这个悲惨的数据库结构。做得好,一旦完成,你将永远感激。

这是经过测试的,可行。可能有更简单的方法(尽可能避免使用动态SQL),但是row_over分区是您正在寻找的。

declare @Table table(
    Customer_No varchar(50), 
    Name varchar(50), 
    Telephone_No varchar(20), 
    Address varchar(50), 
    Street_Name varchar(50), 
    Postcode varchar(50))


insert into @Table
VALUES
(635532, 'Mr. X', '0771111111', 'Flat', '1000 Beach Road', 'Bn23 5HT'),
(635532, 'Mr. X', '0771112222', 'Flat', '1000 Beach Road', 'Bn23 5HT'),
(635532, 'Mr. X', '01903773333', 'Flat', '1000 Beach Road', 'Bn23 5HT')

declare @RowNumberTable table(
    Customer_No varchar(50), 
    Name varchar(50), 
    Telephone_No varchar(50),
    Address varchar(50), 
    Street_Name varchar(50), 
    Postcode varchar(50),
    row_number int)
INSERT INTO @RowNumberTable
SELECT  Customer_No, 
        Name, 
        Telephone_No, 
        Address, 
        Street_Name, 
        Postcode, 
        row_number() over(partition by Customer_No order by Telephone_No) as rn
FROM @Table


SELECT  T1.Customer_No, 
        T1.Name,
        T1.Telephone_No,
        T2.Telephone_No as [Telephone 2],
        T3.Telephone_No as [Telephone 3],
        T4.Telephone_No as [Telephone 4],
        T5.Telephone_No as [Telephone 5],
        T6.Telephone_No as [Telephone 6],
        T7.Telephone_No as [Telephone 7],
        T8.Telephone_No as [Telephone 8],
        T9.Telephone_No as [Telephone 9],
        T10.Telephone_No as [Telephone 10],
        T1.Address,
        T1.Street_Name,
        T1.Postcode
FROM @RowNumberTable T1
LEFT OUTER JOIN @RowNumberTable T2 ON T1.Customer_No = T2.Customer_No AND T2.row_number = 2
LEFT OUTER JOIN @RowNumberTable T3 ON T1.Customer_No = T3.Customer_No AND T3.row_number = 3
LEFT OUTER JOIN @RowNumberTable T4 ON T1.Customer_No = T4.Customer_No AND T4.row_number = 4
LEFT OUTER JOIN @RowNumberTable T5 ON T1.Customer_No = T5.Customer_No AND T5.row_number = 5
LEFT OUTER JOIN @RowNumberTable T6 ON T1.Customer_No = T6.Customer_No AND T6.row_number = 6
LEFT OUTER JOIN @RowNumberTable T7 ON T1.Customer_No = T7.Customer_No AND T7.row_number = 7
LEFT OUTER JOIN @RowNumberTable T8 ON T1.Customer_No = T8.Customer_No AND T8.row_number = 8
LEFT OUTER JOIN @RowNumberTable T9 ON T1.Customer_No = T9.Customer_No AND T9.row_number = 9
LEFT OUTER JOIN @RowNumberTable T10 ON T1.Customer_No = T10.Customer_No AND T10.row_number = 10
WHERE T1.row_number = 1

结果:

Customer_No                                        Name                                               Telephone_No                                       Telephone 2                                        Telephone 3                                        Telephone 4                                        Telephone 5                                        Telephone 6                                        Telephone 7                                        Telephone 8                                        Telephone 9                                        Telephone 10                                       Address                                            Street_Name                                        Postcode
-------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- --------------------------------------------------
635532                                             Mr. X                                              01903773333                                        0771111111                                         0771112222                                         NULL                                               NULL                                               NULL                                               NULL                                               NULL                                               NULL                                               NULL                                               Flat                                               1000 Beach Road                                    Bn23 5HT

答案 3 :(得分:0)

假设表格模式看起来像这样(你需要一种方法来唯一地标识每一行):

create table dbo.customer
(
  customer_no  int         not null ,
  telephone_no varchar(32) not null ,
  name         varchar(32) not null ,
  address      varchar(32) not null ,
  street_name  varchar(32) not null ,
  postcode     varchar(32) not null ,

  primary key clustered ( customer_no , telephone_no ) ,

)

这样的事情可以让你得到你想要的桌子旋转:

with t1 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  group by c.customer_no
) ,
c as (
  select c.*
  from dbo.customer c
  join t1 on t1.customer_no  = c.customer_no
         and t1.telephone_no = c.telephone_no
) ,
t2 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t1           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t3 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t2           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t4 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t3           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t5 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t4           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t6 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t5           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t7 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t6           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t8 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t7           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t9 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t8           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
),
t10 as (
  select customer_no  =      c.customer_no    ,
         telephone_no = min( c.telephone_no )
  from dbo.customer c
  join t9           t on t.customer_no  = c.customer_no
                     and t.telephone_no < c.telephone_no
  group by c.customer_no
)
select customer_no = c.customer_no ,
       name        = c.name        ,
       addr        = c.address     ,
       street      = c.street_name ,
       postcode    = c.postcode    ,
       tel_1       = t1.telephone_no ,
       tel_2       = t2.telephone_no ,
       tel_3       = t2.telephone_no ,
       tel_4       = t2.telephone_no ,
       tel_5       = t2.telephone_no ,
       tel_6       = t2.telephone_no ,
       tel_7       = t2.telephone_no ,
       tel_8       = t2.telephone_no ,
       tel_9       = t2.telephone_no ,
       tel_10      = t2.telephone_no
from      c
left join t1  on t1.customer_no  = c.customer_no and t1.telephone_no  = c.telephone_no
left join t2  on t2.customer_no  = c.customer_no and t2.telephone_no  = c.telephone_no
left join t3  on t3.customer_no  = c.customer_no and t3.telephone_no  = c.telephone_no
left join t4  on t4.customer_no  = c.customer_no and t4.telephone_no  = c.telephone_no
left join t5  on t5.customer_no  = c.customer_no and t5.telephone_no  = c.telephone_no
left join t6  on t6.customer_no  = c.customer_no and t6.telephone_no  = c.telephone_no
left join t7  on t7.customer_no  = c.customer_no and t7.telephone_no  = c.telephone_no
left join t8  on t8.customer_no  = c.customer_no and t8.telephone_no  = c.telephone_no
left join t9  on t9.customer_no  = c.customer_no and t9.telephone_no  = c.telephone_no
left join t10 on t10.customer_no = c.customer_no and t10.telephone_no = c.telephone_no
;