SQL Server - 根据值搜索特定列

时间:2011-02-13 19:20:16

标签: sql sql-server field

我得到了非常宽的月度索引表,如:

index_id | ... | Mar2009 | Apr2009 | May2009 | ... | Feb2010 |
1        | ... | value1  | value2  | value3  | ... | value11 |

有180列,名称分别代表月份和年份(2009年3月,2009年4月,...),大约有5000条记录,此表每月更新。

我还有第二个表格,其中包含以下数据:

index | some other data | index_id | saledate | saleprice | estimated price |
1234  | other data ...  |        1 | 03/05/09 |       100 | ??????????????? |

(大约1百万条记录)我需要根据包括estimated_price在内的索引发送完整记录,计算结果如下: saleprice * ( value1 / value11 ) value1因为saledate id在2009年3月,因为当前月份值为11。

我有2个选项,都需要根据值访问特定列,第二个可以解决:

  1. 飞行计算(我如何根据saledate和当前数据访问索引表中的正确列) - 请注意数据表很大而且索引也不是小的

  2. 当更新索引表运行作业以计算估计价格时,将其置于数据表中,如何与上述问题相同(如何根据saledate访问索引表中的正确列

  3. 第一个解决方案看起来效果看起来更有效,但我担心更新过程可能需要太长时间...我认为一个停滞不前的表会将宽索引表转换为长表,如:

    index_id | date_from_column | index_value |
    

    这种方式可以更容易合并表,但是我需要在更新索引表后使用TRUNCATE长表并运行180个INSERT,如:

    INSERT INTO long_table SELECT index_id, 'Mar2009' AS date_from_column, Mar2009 AS index_value FROM indexes_table

    其中每个下一个INSERT将具有下一个列名称形式索引

1 个答案:

答案 0 :(得分:3)

从根本上说,你遇到的问题是你的设计没有规范化,结果是提取信息的查询更加困难。具体来说,第一个表的结构应为:

Create Table MonthlyIndexes As
    (
    index_id int not null
    , date datetime not null
    , value ...
    , Primary Key ( index_id, date )
    , Constraint CK_MonthlyIndexes_Date Check ( DatePart(d, date) = 1 )
    )
index_id | date     | value
--------   --------   -------
1        | 20090301 | ...
1        | 20090401 | ...
...

现在,检索所需信息的查询变得更加简单:

Select S.saleprice * ( MStart.value / MEnd.value )
From Sales As S
    Join MonthlyIndexes As MStart
        On MStart.date = DateAdd(d, -DatePart(d, S.saledate) + 1)
    Join MonthlyIndexes As MEnd
        On MEnd.date = DateAdd(d, -DatePart(d, CURRENT_TIMESTAMP) + 1)

除非重构您的架构,否则您可以像这样模拟正确的设计(假设SQL Server 2005 +):

With Indexes As
    (
    Select index_id, Cast('20090301' As datetime) as date, Mar2009
    From MonthlyIndexes
    Union All
    Select index_id, Cast('20090401' As datetime) as date, Apr2009
    From MonthlyIndexes
    ....
    Union All
    Select index_id, Cast('20100201' As datetime) as date, Feb2010
    From MonthlyIndexes
    )
Select S.saleprice * ( MStart.value / MEnd.value )
From Sales As S
    Join MonthlyIndexes As MStart
        On MStart.date = DateAdd(d, -DatePart(d, S.saledate) + 1)
    Join MonthlyIndexes As MEnd
        On MEnd.date = DateAdd(d, -DatePart(d, CURRENT_TIMESTAMP) + 1)

如果月度索引表很大,您可以对规范化表进行期间更新,并将其用于查询。

另一种解决方案是使用类似于CTE中的Union All查询的查询定期更新临时表,其中数据结构正确。如果数据每月添加一次,您甚至可以添加一个计划存储过程,检查是否存在给定月份的列并附加该月份的数据。这将涉及我通常建议反对的动态SQL,但是对于维护解决方案,它可能会解决问题(直到你说服管理层纠正架构)。