存储数据范围的颜色并用于 SQL 服务器中的 case 语句
Store color for data ranges and use in case statement in SQL Server
我有如下数据集。 Fiddle URL
我需要使用上面 table 中的运算符获取给定数字的颜色 table。
例如;
当我调用函数getColor(6)
时,应该return PURPLE
.
当我调用函数getColor(0)
时,应该return RED
.
我怎样才能做到这一点?
最简单的解决方案是使用 CASE
表达式为每个运算符创建匹配条件:
DECLARE @val NUMERIC(10) = 6;
SELECT /* TOP 1 */ *
FROM #range_color
CROSS APPLY (SELECT @val - range_number) AS ca(diff)
WHERE CASE WHEN diff < 0 AND range_operator = '<' THEN 1 END = 1
OR CASE WHEN diff <= 0 AND range_operator = '<=' THEN 1 END = 1
OR CASE WHEN diff >= 0 AND range_operator = '>=' THEN 1 END = 1
OR CASE WHEN diff > 0 AND range_operator = '>' THEN 1 END = 1
ORDER BY ABS(diff)
你能试试下面的查询吗
CREATE FUNCTION getColor
(@Colorcode decimal(18,2))
RETURNS VARCHAR(10)
AS
BEGIN
DECLARE @color VARCHAR(10)='RED'
SELECT TOP (1) @color=range_color FROM range_color
WHERE range_number between range_number AND @Colorcode - (CASE WHEN
@Colorcode=0 THEN 1 ELSE 0 END) Order by range_number desc
RETURN @color
END
我试过另一个查询,
DECLARE @val DECIMAL(18,2)=1
DECLARE @temp TABLE(color VARCHAR(10),flag BIT,range_number NUMERIC(10),diff int)
DECLARE @temp1 TABLE(color VARCHAR(10),range_number NUMERIC(10),Operator VARCHAR(10),range_color_id INT)
INSERT INTO @temp1
SELECT range_color,range_number,range_operator,range_color_id FROM range_color
WHILE(0<(SELECT COUNT(1) FROM @temp1))
BEGIN
DECLARE @operator VARCHAR(10),@range_color_id INT
SELECT TOP 1 @operator=Operator,@range_color_id=range_color_id FROM @temp1
INSERT INTO @temp
EXEC ('select range_color,CASE WHEN '+ @val +' '+@operator+' range_number
THEN 1 else 0 END,range_number,'+@val+'- range_number from range_color WHERE
range_color_id='+@range_color_id)
DELETE TOP (1) FROM @temp1
END
SELECT * FROM @temp WHERE flag=1 ORDER BY ABS(diff)
请您查看以下查询。
declare @PassingValues int = 0
declare @MatchingRange int
select top 1 @MatchingRange = range_number from #RangeColor where range_number = @PassingValues
order by range_color_id
if(@@ROWCOUNT <= 0)
begin
if(@MatchingRange is not null)
begin
select top 1 * from #RangeColor where range_number <= @MatchingRange
order by range_color_id
end
else
begin
Select top 1 @MatchingRange = range_number from #RangeColor where range_number < @PassingValues
order by range_number desc
if(@MatchingRange IS NULL)
begin
select top 1 @MatchingRange = range_number from #RangeColor where range_number > @PassingValues
order by range_number
select top 1 * from #RangeColor where range_number > @MatchingRange
order by range_color_id
end
else
begin
select top 1 * from #RangeColor where range_number <= @MatchingRange
order by range_color_id desc
end
end
end
else
begin
select top 1 * from #RangeColor where range_number = @PassingValues
order by range_color_id
end
好吧,如果您打算打印这些值在范围内,您可以使用以下存储过程:
Create Proc MyProc(@Range Int)
As
Begin
Select @Range As RangeValue, Case When @Range = 0 Then
'Red'
When @Range > 0 And @Range<5 Then
'Blue'
When @Range >= 5 And @Range <8 Then
'Purple'
When @Range >= 8 And @Range <12 Then
'Orange'
When @Range >=12 Then
'Green'
End As ColorName
End
Go
-- execute procedure..
Exec MyProc 3
我建议将您的 table 更改为更易于解释和查询的内容。以下语句创建新的 table 并将您的规则转换为新格式。稍后您会看到查询这个新的 table.
是多么容易
我建议的table每种颜色都有下限+上限:
CREATE TABLE UpdatedRangeColor (
range_color_id INT PRIMARY KEY,
range_color VARCHAR(50) NOT NULL,
LowerLimit INT,
HigherLimit INT)
这会将当前规则转换为新规则 table:
CREATE TABLE UpdatedRangeColor (
range_color_id INT PRIMARY KEY,
range_color VARCHAR(50) NOT NULL,
LowerLimit INT,
HigherLimit INT)
;WITH HigherRule AS
(
SELECT
R.*,
IsRuleHigher = CASE WHEN R.range_operator LIKE '%>%' THEN 1 ELSE 0 END
FROM
range_color AS R
),
TemporaryLimits AS
(
select
R.*,
TemporaryLowerLimit = CASE WHEN R.IsRuleHigher = 1 THEN R.range_number END,
TemporaryHigherLimit = CASE WHEN R.IsRuleHigher = 0 THEN R.range_number END,
Partition = ROW_NUMBER() OVER (
PARTITION BY
CASE WHEN R.IsRuleHigher = 1 THEN 1 ELSE 2 END
ORDER BY
ABS(R.range_number))
from
HigherRule AS R
)
INSERT INTO UpdatedRangeColor (
range_color_id,
range_color,
LowerLimit,
HigherLimit)
SELECT
T.range_color_id,
T.range_color,
LowerLimit = CASE
WHEN T.IsRuleHigher = 1 THEN T.TemporaryLowerLimit
ELSE LAG(T.TemporaryHigherLimit, 1, -999) OVER (PARTITION BY T.IsRuleHigher ORDER BY T.Partition DESC) END,
HigherLimit = CASE
WHEN T.IsRuleHigher = 1 THEN LEAD(T.TemporaryLowerLimit, 1, 999) OVER (PARTITION BY T.IsRuleHigher ORDER BY T.Partition ASC)
ELSE T.TemporaryHigherLimit END
FROM
TemporaryLimits AS T
插入的行如下:
range_color_id range_color LowerLimit HigherLimit
1 RED -999 0
2 BLUE 0 5
3 PURPLE 5 8
4 ORANGE 8 12
5 GREEN 12 999
然后您可以简单地发出带有 2 个条件的直接查询(确保查看应包含等号的位置):
DECLARE @ParameterValue FLOAT = 5.648
SELECT
*
FROM
UpdatedRangeColor AS U
WHERE
@ParameterValue >= U.LowerLimit AND
@ParameterValue < U.HigherLimit
结果:
range_color_id range_color LowerLimit HigherLimit
3 PURPLE 5 8
这种方法的缺点是维护这个新的 table,您必须在插入新值或更新时保持记录的一致性(或使用此过程将原始行转换为新格式添加新记录的时间)。
我有如下数据集。 Fiddle URL
我需要使用上面 table 中的运算符获取给定数字的颜色 table。
例如;
当我调用函数getColor(6)
时,应该return PURPLE
.
当我调用函数getColor(0)
时,应该return RED
.
我怎样才能做到这一点?
最简单的解决方案是使用 CASE
表达式为每个运算符创建匹配条件:
DECLARE @val NUMERIC(10) = 6;
SELECT /* TOP 1 */ *
FROM #range_color
CROSS APPLY (SELECT @val - range_number) AS ca(diff)
WHERE CASE WHEN diff < 0 AND range_operator = '<' THEN 1 END = 1
OR CASE WHEN diff <= 0 AND range_operator = '<=' THEN 1 END = 1
OR CASE WHEN diff >= 0 AND range_operator = '>=' THEN 1 END = 1
OR CASE WHEN diff > 0 AND range_operator = '>' THEN 1 END = 1
ORDER BY ABS(diff)
你能试试下面的查询吗
CREATE FUNCTION getColor
(@Colorcode decimal(18,2))
RETURNS VARCHAR(10)
AS
BEGIN
DECLARE @color VARCHAR(10)='RED'
SELECT TOP (1) @color=range_color FROM range_color
WHERE range_number between range_number AND @Colorcode - (CASE WHEN
@Colorcode=0 THEN 1 ELSE 0 END) Order by range_number desc
RETURN @color
END
我试过另一个查询,
DECLARE @val DECIMAL(18,2)=1
DECLARE @temp TABLE(color VARCHAR(10),flag BIT,range_number NUMERIC(10),diff int)
DECLARE @temp1 TABLE(color VARCHAR(10),range_number NUMERIC(10),Operator VARCHAR(10),range_color_id INT)
INSERT INTO @temp1
SELECT range_color,range_number,range_operator,range_color_id FROM range_color
WHILE(0<(SELECT COUNT(1) FROM @temp1))
BEGIN
DECLARE @operator VARCHAR(10),@range_color_id INT
SELECT TOP 1 @operator=Operator,@range_color_id=range_color_id FROM @temp1
INSERT INTO @temp
EXEC ('select range_color,CASE WHEN '+ @val +' '+@operator+' range_number
THEN 1 else 0 END,range_number,'+@val+'- range_number from range_color WHERE
range_color_id='+@range_color_id)
DELETE TOP (1) FROM @temp1
END
SELECT * FROM @temp WHERE flag=1 ORDER BY ABS(diff)
请您查看以下查询。
declare @PassingValues int = 0
declare @MatchingRange int
select top 1 @MatchingRange = range_number from #RangeColor where range_number = @PassingValues
order by range_color_id
if(@@ROWCOUNT <= 0)
begin
if(@MatchingRange is not null)
begin
select top 1 * from #RangeColor where range_number <= @MatchingRange
order by range_color_id
end
else
begin
Select top 1 @MatchingRange = range_number from #RangeColor where range_number < @PassingValues
order by range_number desc
if(@MatchingRange IS NULL)
begin
select top 1 @MatchingRange = range_number from #RangeColor where range_number > @PassingValues
order by range_number
select top 1 * from #RangeColor where range_number > @MatchingRange
order by range_color_id
end
else
begin
select top 1 * from #RangeColor where range_number <= @MatchingRange
order by range_color_id desc
end
end
end
else
begin
select top 1 * from #RangeColor where range_number = @PassingValues
order by range_color_id
end
好吧,如果您打算打印这些值在范围内,您可以使用以下存储过程:
Create Proc MyProc(@Range Int)
As
Begin
Select @Range As RangeValue, Case When @Range = 0 Then
'Red'
When @Range > 0 And @Range<5 Then
'Blue'
When @Range >= 5 And @Range <8 Then
'Purple'
When @Range >= 8 And @Range <12 Then
'Orange'
When @Range >=12 Then
'Green'
End As ColorName
End
Go
-- execute procedure..
Exec MyProc 3
我建议将您的 table 更改为更易于解释和查询的内容。以下语句创建新的 table 并将您的规则转换为新格式。稍后您会看到查询这个新的 table.
是多么容易我建议的table每种颜色都有下限+上限:
CREATE TABLE UpdatedRangeColor (
range_color_id INT PRIMARY KEY,
range_color VARCHAR(50) NOT NULL,
LowerLimit INT,
HigherLimit INT)
这会将当前规则转换为新规则 table:
CREATE TABLE UpdatedRangeColor (
range_color_id INT PRIMARY KEY,
range_color VARCHAR(50) NOT NULL,
LowerLimit INT,
HigherLimit INT)
;WITH HigherRule AS
(
SELECT
R.*,
IsRuleHigher = CASE WHEN R.range_operator LIKE '%>%' THEN 1 ELSE 0 END
FROM
range_color AS R
),
TemporaryLimits AS
(
select
R.*,
TemporaryLowerLimit = CASE WHEN R.IsRuleHigher = 1 THEN R.range_number END,
TemporaryHigherLimit = CASE WHEN R.IsRuleHigher = 0 THEN R.range_number END,
Partition = ROW_NUMBER() OVER (
PARTITION BY
CASE WHEN R.IsRuleHigher = 1 THEN 1 ELSE 2 END
ORDER BY
ABS(R.range_number))
from
HigherRule AS R
)
INSERT INTO UpdatedRangeColor (
range_color_id,
range_color,
LowerLimit,
HigherLimit)
SELECT
T.range_color_id,
T.range_color,
LowerLimit = CASE
WHEN T.IsRuleHigher = 1 THEN T.TemporaryLowerLimit
ELSE LAG(T.TemporaryHigherLimit, 1, -999) OVER (PARTITION BY T.IsRuleHigher ORDER BY T.Partition DESC) END,
HigherLimit = CASE
WHEN T.IsRuleHigher = 1 THEN LEAD(T.TemporaryLowerLimit, 1, 999) OVER (PARTITION BY T.IsRuleHigher ORDER BY T.Partition ASC)
ELSE T.TemporaryHigherLimit END
FROM
TemporaryLimits AS T
插入的行如下:
range_color_id range_color LowerLimit HigherLimit
1 RED -999 0
2 BLUE 0 5
3 PURPLE 5 8
4 ORANGE 8 12
5 GREEN 12 999
然后您可以简单地发出带有 2 个条件的直接查询(确保查看应包含等号的位置):
DECLARE @ParameterValue FLOAT = 5.648
SELECT
*
FROM
UpdatedRangeColor AS U
WHERE
@ParameterValue >= U.LowerLimit AND
@ParameterValue < U.HigherLimit
结果:
range_color_id range_color LowerLimit HigherLimit
3 PURPLE 5 8
这种方法的缺点是维护这个新的 table,您必须在插入新值或更新时保持记录的一致性(或使用此过程将原始行转换为新格式添加新记录的时间)。