如何为两列值的范围实现查找表

时间:2012-02-07 19:35:11

标签: .net sql-server database winforms visual-studio-2010

修改:更新了两个表,以便彼此同步。这些是唯一涉及的表格。简单地说,我需要计算所有唯一记录并以2d格式显示它。

我有一张光学镜片表,其样本如下:

            Spherical|Cylindrical
            ---------------------
             0       |    0.5
             0.25    |    0.75
             0.25    |    0.5
             0       |    0
             0       |    0.25
             0       |    0.5
             0.25    |    0.75
             0.25    |    0.5
             0.5     |    0
             0.75    |    0
             0.75    |    0
             0.5     |    0.25
             0.5     |    0.75
             0.75    |    0.25
             0.5     |    0.75
             0.75    |    0.75
             0.75    |    0.5
             0.75    |    0.5

依旧......

我希望以这种方式以2d格式显示每只组合中镜头数量的鸟瞰图:

Spherical/Cylindrical|0|0.25|0.5|0.75|... upto 8 in steps of 0.25
-----------------------------------------     
                 0   |1|  1 | 2 | 1  |
               0.25  |0|  0 | 2 | 2  |
               0.5   |1|  2 | 0 | 2  |
               0.75  |2|  1 | 2 | 1  |
                ...
               upto 30 in steps of 0.25

如何使用sql server 2008在c#.net中实现此功能?哪种方法最好?

我有几点想法:

  1. 使用一些特殊查询在运行时生成视图并对其进行格式化 在2d
  2. 创建一个2d表格(以上面的格式)并更新 每次镜头表更新时计数。
  3. 请告诉我你的想法并就此提出建议。谢谢!

2 个答案:

答案 0 :(得分:2)

这是一个关于如何制作视图的示例查询:

--build table variable and sample data
DECLARE @Optical table (Spherical numeric(4,2),Cylindrical numeric(4,2))
INSERT INTO @Optical VALUES (   0, 0.5)
INSERT INTO @Optical VALUES (0.25,0.75)
INSERT INTO @Optical VALUES (1.25, 0.5)
INSERT INTO @Optical VALUES (1.25, 0.5)
INSERT INTO @Optical VALUES (   0,  0)

--query to use as a basis for the view
;with AllSpherical AS --this recursive CTE builds the 121 rows for: 0.00 to 30.0
(
    SELECT convert(numeric(4,2),0.0) AS Spherical
    UNION ALL
    SELECT convert(numeric(4,2),Spherical+0.25)
        FROM AllSpherical
    WHERE Spherical<=29.75
)
SELECT 
    s.Spherical 
        ,SUM(CASE WHEN o.Cylindrical=0.00 THEN 1 ELSE 0 END) AS c_000
        ,SUM(CASE WHEN o.Cylindrical=0.25 THEN 1 ELSE 0 END) AS c_025
        ,SUM(CASE WHEN o.Cylindrical=0.50 THEN 1 ELSE 0 END) AS c_050
        ,SUM(CASE WHEN o.Cylindrical=0.75 THEN 1 ELSE 0 END) AS c_075
        ,SUM(CASE WHEN o.Cylindrical=1.00 THEN 1 ELSE 0 END) AS c_100
        ,SUM(CASE WHEN o.Cylindrical=1.25 THEN 1 ELSE 0 END) AS c_125
        ,SUM(CASE WHEN o.Cylindrical=1.50 THEN 1 ELSE 0 END) AS c_150
        ,SUM(CASE WHEN o.Cylindrical=1.75 THEN 1 ELSE 0 END) AS c_175
        --... add a case for all columns

    FROM AllSpherical              s
        LEFT OUTER JOIN @Optical   o ON s.Spherical=o.Spherical
    GROUP BY s.Spherical 
    OPTION (MAXRECURSION 120)

输出:

Spherical  c_000 c_025 c_050 c_075 c_100 c_125 c_150 c_175
---------- ----- ----- ----- ----- ----- ----- ----- -----
0.00       1     0     1     0     0     0     0     0
0.25       0     0     0     1     0     0     0     0
0.50       0     0     0     0     0     0     0     0
0.75       0     0     0     0     0     0     0     0
1.00       0     0     0     0     0     0     0     0
1.25       0     0     2     0     0     0     0     0
1.50       0     0     0     0     0     0     0     0
1.75       0     0     0     0     0     0     0     0
2.00       0     0     0     0     0     0     0     0
2.25       0     0     0     0     0     0     0     0
...

(121 row(s) affected)

如果更新原始数据比使用此视图更多,则可以使用此查询构建传统视图。这将是你的选择1

如果您计划阅读此视图的次数远远超过更新原始数据,请考虑保留视图:Improving Performance with SQL Server 2005 Indexed Views Creating Indexed Views。这基本上实现了视图,当您插入/更新/删除基础表时,视图的存储数据更新就像自动系统级触发器一样,以使它们保持同步。这将是你的选择2,但系统会做所有“艰难”的工作,保持一切都同步。

答案 1 :(得分:2)

借用KM的表变量,这是使用PIVOT并避免33个SUM(CASE...)表达式的另一种方法。

DECLARE @Optical TABLE (Spherical DECIMAL(4,2), Cylindrical DECIMAL(4,2));

INSERT INTO @Optical VALUES (   0, 0.5);
INSERT INTO @Optical VALUES (0.25, 0.75);
INSERT INTO @Optical VALUES (1.25, 0.5);
INSERT INTO @Optical VALUES (1.25, 0.5);
INSERT INTO @Optical VALUES (   0, 0);

;WITH x AS 
(
    SELECT TOP (33) [row] = (ROW_NUMBER() 
        OVER (ORDER BY [object_id])-1)*0.25
        FROM sys.objects ORDER BY [row]
), y AS
(
    SELECT Spherical = x.[row], o.Cylindrical
        FROM x 
        LEFT OUTER JOIN @Optical AS o
        ON x.[row] = o.Spherical
)
SELECT pvt.* FROM y 
PIVOT (COUNT(y.Cylindrical) FOR y.Cylindrical IN 
(
  [0.00],[0.25],[0.50],[0.75],[1.00],[1.25],[1.50],[1.75],[2.00],[2.25],[2.50],[2.75],
  [3.00],[3.25],[3.50],[3.75],[4.00],[4.25],[4.50],[4.75],[5.00],[5.25],[5.50],[5.75],
  [6.00],[6.25],[6.50],[6.75],[7.00],[7.25],[7.50],[7.75],[8.00]
)) AS pvt
ORDER BY pvt.Spherical;

现在,您可能在想,我不想在PIVOT部分输入所有这些值,但您可以非常快速地生成这些值:

DECLARE @sql NVARCHAR(MAX)= N'';

;WITH x AS 
(
    SELECT TOP (33) [row] = (ROW_NUMBER() 
        OVER (ORDER BY [object_id])-1)*0.25
        FROM sys.objects ORDER BY [row]
)
SELECT @sql = @sql + ',[' + RTRIM(CONVERT(DECIMAL(4,2), [row])) + ']' FROM x;

SET @sql = STUFF(@sql, 1, 1, '');

PRINT @sql;