如何编写将逗号分隔的字段扩展为多个字段的SQL查询?

时间:2016-05-16 01:37:20

标签: mysql

首先......我知道在表格中使用逗号分隔值是不好的,我不能改变它。

我有几个包含以下数据的表:

************** Table 1 **********
stock_id   products_id   stock_attributes 
   5271       279           1559,2764

************** Table 2 *********************
products_attributes_id   products_id   options_id   options_values_id
   1559                     279             2               8
   2764                     279             3               63

************** Table 3 ************************
products_options_id     products_options_name
    2                       Size
    3                       Color

************** Table 4 *****************
products_options_values_id      products_options_values_name
    14                                  Pink
    63                                  Mint
    13                                  Black
    8                                   S
    9                                   M
    10                                  L
    11                                  XL

我想要做的是创建一个查询,以获取表1中的字段stock_attributes,并使用表2,3和2中的信息展开它。 4所以我最终得到以下结论:

*********** Resulting Table **********
stock_id    products_id     opt1  opt2  opt3   opt4     
5271        279             Size  S     Color  Mint     

我可以在事后以编程方式执行此操作,但我很好奇是否可以在单个SQL查询中完成。我已经找到了类似的问题和答案,如何从逗号分隔的字段中选择一个特定的值,但没有做到这一点。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:0)

如果属性数量是固定的。您可以简单地将列拆分为多个。

SELECT stock_id, products_id,
    PARSENAME(REPLACE(stock_attributes,',','.'),2) a1, 
PARSENAME(REPLACE(stock_attributes,',','.'),1) a2
FROM Table1

要进一步扩展并包含其他表中的值,您可以执行简单的JOIN

select pTable.stock_id, pTable.products_id, 
    (select products_options_name from Table3 where products_options_id = t2.options_id) as opt1,
    (select products_options_values_name from Table4 where products_options_values_id = t2.options_values_id) as opt2,
    (select products_options_name from Table3 where products_options_id = t3.options_id) as opt3,
    (select products_options_values_name from Table4 where products_options_values_id = t3.options_values_id) as opt4
from 
(
    SELECT stock_id, products_id,
        PARSENAME(REPLACE(stock_attributes,',','.'),2) a1, 
    PARSENAME(REPLACE(stock_attributes,',','.'),1) a2
    FROM Table1
) pTable
join Table2 t2 on pTable.a1 = t2.products_attributes_id and pTable.products_id = t2.products_id   
join Table2 t3 on pTable.a2 = t3.products_attributes_id and pTable.products_id = t3.products_id  

答案 1 :(得分:0)

这很长。所以我会停下来,直到数据准备好 Dynamic SQL Pivot

这可以解决任意数量的属性。只需将输出保存到表中o创建存储过程以获取动态数据透视的数据。

  1. tmp: Split 以逗号分隔的行数

  2. product_attributes:只是一个选择来查看递归函数的结果。无法删除

  3. product_details:将属性与其他表连接以获取其值

  4. product_attribute_count:每个属性都需要row_number,因此您可以稍后创建标题。我也意识到你不需要COUNT()

  5. product_pre_pivot:为option_idoption_value_id创建标题和值

  6. product_pivot:将这些对标题分隔为单个列

  7. 您可以测试每个步骤以查看结果.... SELECT * FROM [STEP#]

    <强> SQL Fiddle Demo

    代码:

    ;WITH tmp([stock_id], [products_id], products_attributes_id, data_r) AS   
    (
        SELECT 
            [stock_id], [products_id], 
            LEFT([stock_attributes], Charindex(',', [stock_attributes] + ',') - 1), 
            STUFF([stock_attributes], 1, Charindex(',', [stock_attributes] + ','), '') 
        FROM   
            Table1 
    
        UNION ALL 
    
        SELECT 
            [stock_id], [products_id], 
            LEFT(data_r, Charindex(',', data_r + ',') - 1), 
            STUFF(data_r, 1, Charindex(',', data_r + ','), '') 
        FROM   
            tmp 
        WHERE  
            data_r > ''
    ), product_attributes AS 
    (         
        SELECT 
            [stock_id], [products_id], 
            [products_attributes_id]
        FROM   
            tmp 
    ), product_details AS 
    (        
        SELECT 
            pa.*, 
            t2.options_id, t2.options_values_id,
            t3.[products_options_name],
            t4.[products_options_values_name]
        FROM 
            product_attributes pa
        JOIN 
            Table2 t2 ON pa.[products_id] = t2.[products_id]
                      AND pa.[products_attributes_id] = t2.[products_attributes_id]
        JOIN 
            Table3 t3 ON t2.[options_id] = t3.[products_options_id] 
        JOIN 
            Table4 t4 ON t2.[options_values_id] = t4.[products_options_values_id]
    ), product_attribute_count AS 
    (           
        SELECT 
            *,
            row_number() over (PARTITION BY products_id 
                               ORDER BY options_id) as rn,
            count(*) over (partition by products_id) cnt
        FROM 
            product_details
    ), product_pre_pivot AS 
    ( 
        SELECT 
            stock_id, products_id,    
            'opt' + CAST(2*rn - 1 as varchar(max))  as header1,
            products_options_name as d_value,
            'opt' + CAST(2*rn  as varchar(max)) as header2,
            products_options_values_name as a_value
        FROM 
            product_attribute_count
    ), product_pivot AS 
    (  
        SELECT 
            stock_id, products_id,
            header1 header, d_value value
        FROM 
            product_pre_pivot
    
        UNION ALL
    
        SELECT 
            stock_id, products_id,
            header2 header, a_value value
        FROM 
            product_pre_pivot 
    )
    SELECT *
    FROM product_pivot
    ORDER BY header
    

    <强>输出

    | stock_id | products_id | header | value |
    |----------|-------------|--------|-------|
    |     5271 |         279 |   opt1 |  Size |
    |     5271 |         279 |   opt2 |     S |
    |     5271 |         279 |   opt3 | Color |
    |     5271 |         279 |   opt4 |  Mint |