【问题标题】:How to implement a look up table for a range of values of two columns如何为两列的值范围实现查找表
【发布时间】:2025-11-25 09:45:01
【问题描述】:

编辑:更新了两个表以相互同步。这些是唯一涉及的表。简单地说,我需要计算所有唯一记录并以二维格式显示。

我有一张光学镜片表,下面是一个示例:

            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

如何在 c#.net 中使用 sql server 2008 实现这一点?哪种方法最好?

我有几个想法:

  1. 在运行时使用一些特殊查询生成视图并对其进行格式化 二维
  2. 创建一个 2d 表类型(以上述格式)并更新 每次更新镜头表时计数。

请给我你的想法和建议。谢谢!

【问题讨论】:

  • 我肯定会选择 1(必须不断更新数据意味着它总是会过时,除非你使用触发器,这会很糟糕)。但是我很难理解数据的实际来源。您能否展示样本数据以及计数是如何得出的?
  • 我假设您还漏掉了另一张桌子,对吧?一个持有每个镜头数量的镜头。
  • @AaronBertrand 我已经更新了两个表以相互同步。请看一看。谢谢!

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


【解决方案1】:

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

--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,但系统会做所有“艰苦”的工作来保持一切同步。

【讨论】:

  • 感谢一百万!看起来这就是我需要的。我需要将此视图显示为默认页面,所以我想我应该使用选项 2。我是 .net 和 sqls 的完整新手。(我来自大型机/cobol,正在尝试其他“真实” ' 编程语言).. 我会试试这个并更新你。非常感谢!
  • 我试过了,效果很好!谢谢一百万!
【解决方案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;

【讨论】:

  • 绝对 +1,用于动态 SQL。
  • OP 只想要 33 列 up to 8 in steps of 0.25,这比您的声明要少得多:avoids 121 SUM(CASE...) expressions.
  • 哎呀,我以为两边都是30。
  • 这个也很完美!太感谢了! SO中有没有办法接受两个答案?