Сохранение цвета для диапазонов данных и использование оператора case в SQL Server - PullRequest
0 голосов
/ 20 февраля 2019

У меня есть набор данных, как показано ниже. Fiddle URL

enter image description here

Мне нужно получить цвет данного числа, используя операторы в приведенной выше таблице.

Например;

Когда я вызывал функцию getColor(6), должен возвращаться PURPLE.

Когда я вызывал функцию getColor(0), должен возвращаться RED.

Как я мог достичь этого?

Ответы [ 5 ]

0 голосов
/ 20 февраля 2019

Я предлагаю изменить вашу таблицу на что-то более простое для интерпретации и запроса.Следующие операторы создают новую таблицу и преобразуют ваши правила в новый формат.Позже вы увидите, насколько просто запросить эту новую таблицу.

Предлагаемая таблица имеет нижний + верхний предел для каждого цвета:

CREATE TABLE UpdatedRangeColor (
    range_color_id INT PRIMARY KEY,
    range_color VARCHAR(50) NOT NULL,
    LowerLimit INT,
    HigherLimit INT)

Это преобразует текущие правила в новую таблицу:

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

Затем вы можете просто выполнить прямой запрос с двумя условиями (обязательно проверьте, где должен быть включен знак равенства):

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

Недостатком этого подхода является поддержание этой новой таблицы, вам придется сохранять согласованность записей при вставке новых значений или обновлении (или использовать этопроцедура перевода исходных строк в новый формат каждый раз, когда добавляются новые записи).

0 голосов
/ 20 февраля 2019

Хорошо, если ваше намерение распечатать эти значения лежит в диапазоне, вы можете использовать следующую хранимую процедуру:

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
0 голосов
/ 20 февраля 2019

Можете ли вы попробовать следующий запрос.

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)
0 голосов
/ 20 февраля 2019

Просим вас ознакомиться с приведенным ниже запросом.

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
0 голосов
/ 20 февраля 2019

Самое простое решение - создать условие соответствия для каждого оператора, используя выражения 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...