在SQL中的Max / Min Columns中对值进行分类

时间:2013-12-09 15:41:16

标签: sql sql-server tsql sql-server-2012 unpivot

使用SQL Server 2012,我有一个类似这样的分类表:

prodName   class1min   class1max   class2min   class2max   class3min   class3max
---------------------------------------------------------------------------------
prod A      1.5         1.8         1.8         2.1         2.1         2.5
prod B      3.6         3.9         3.9         4.5         4.5         5.6
prod C      2.7         3.2         3.2         3.6         3.6         4.2
etc...

给定产品名称和值,我需要找到我的值所属的分类(1,2或3)。

即。我有一个产品B项,其值为4.1。我只需要能够确定它属于第2类。

到目前为止,我已经尝试根据选择的产品创建unpivot表,如下所示:

产品B:

class       value
------------------
class1min   3.6
class1max   3.9
class2min   3.9
class2max   4.5
class3min   4.5
class3max   5.6

然后通过插入我的值和排序,我至少能够看到分类。

class       value
------------------
class1min   3.6
class1max   3.9
class2min   3.9
myvalue     4.1
class2max   4.5
class3min   4.5
class3max   5.6

我仍然无法通过代码隔离它,我认为可能有更好的方法。

注意:在平局的情况下,我想要较低的分类。

5 个答案:

答案 0 :(得分:2)

您可以取消数据,然后执行比较。由于您使用的是SQL Server 2012,因此您可以使用CROSS APPLY轻松地将min / max列中的{@ 1}} / select prodname, class, [min], [max] from yourtable cross apply ( values ('class1', class1min, class1max), ('class2', class2min, class2max), ('class3', class3min, class3max) ) c(class, [min], [max]) 列展开:

DECLARE @Prod VARCHAR(32) = 'Prod B', 
  @val DECIMAL(10,2) = 4.1;

select prodname, class, [min], [max]
from yourtable
cross apply
(
  values
    ('class1', class1min, class1max),
    ('class2', class2min, class2max),
    ('class3', class3min, class3max)
) c(class, [min], [max])
where prodname = @Prod
  and @val > [min]
  and @val <= [max]

Demo。一旦数据被取消,您就可以比较您的价值以找到该类。如果您有更多分类,则可以在子查询中轻松添加更多值:

{{1}}

请参阅SQL Fiddle with Demo

答案 1 :(得分:1)

由于只有三个可能的类,因此您可以使用CASE表达式完成此任务:

DECLARE @Prod VARCHAR(32) = 'Prod B', @val DECIMAL(10,2) = 4.1;

SELECT [Class] = CASE WHEN @val <= class1max THEN 'Class1'
    WHEN @val > class3Min THEN 'Class3' ELSE 'Class2' END
FROM dbo.tableName
WHERE ProdName = @Prod;

现在我们知道“问题”是你实际上有9个分类,而不是问题中陈述的3个分类,这仍然可以扩展:

DECLARE @Prod VARCHAR(32) = 'Prod B', @val DECIMAL(10,2) = 4.1;

SELECT [Class] = CASE WHEN @val <= class1max THEN 'Class1'
    WHEN @val > class2Min AND @val <= class2Max THEN 'Class2'
    WHEN @val > class3Min AND @val <= class3Max THEN 'Class3'
    WHEN @val > class4Min AND @val <= class4Max THEN 'Class4'
    WHEN @val > class5Min AND @val <= class5Max THEN 'Class5'
    WHEN @val > class6Min AND @val <= class6Max THEN 'Class6'
    WHEN @val > class7Min AND @val <= class7Max THEN 'Class7'
    WHEN @val > class8Min AND @val <= class8Max THEN 'Class8'
    ELSE 'Class9' END
FROM dbo.tableName
WHERE ProdName = @Prod;

如果问题在于代码太多,那么你可以考虑改变设计。

答案 2 :(得分:0)

如已评论,您可以简单地将数据规范化为多个表。 e.g。

Product
--------
id_Product
name
moreProductRelatedColumns

ProductClassification
--------------
id_Classification
classCode
fk_productId
min
max

然后你可以选择:

Select classCode 
from Products join ProductClassification pc on id_Product = fk_productId
where value between pc.min and pc.max

在当前的表设计中,您可以使用嵌套的CASE WHEN语句。但是我建议使用规范化的表设计,因为在没有重写查询的情况下添加或删除Products中的类没有问题。

答案 3 :(得分:0)

DECLARE @target_product varchar(32) = 'prod B'
DECLARE @target_value decimal(9,2) = 4.1

SELECT LEFT([class],6)
FROM MyTable
UNPIVOT([value] FOR [class] IN (
  [class1min],[class1max],
  [class2min],[class2max],
  [class3min],[class3max]
)) p1
WHERE @target_product = [prodName]
GROUP BY prodName,LEFT([class],6)
HAVING @target_value >= MIN([value]) AND @target_value < MAX([value])

答案 4 :(得分:0)

好吧,既然你问,一个标准化的方法可能看起来像这样[在[prodname,class]上形成PK] ......

prodName   class  min    max  
prod A      1     1.5    1.8   
prod B      1     3.6    3.9   
prod C      1     2.7    3.2   
prod A      2     1.8    2.1   
prod B      2     3.9    4.5   
prod C      2     3.2    3.6   
prod A      3     2.1    2.5
prod B      3     4.5    5.6
prod C      3     3.6    4.2