【问题标题】:How to build a where statement based on dynamic conditions如何根据动态条件构建 where 语句
【发布时间】:2021-04-02 17:53:12
【问题描述】:

由于业务复杂性,我们必须有一个动态条件表。

我们的表格叫做“规则”

它有这个结构

ID  Field        Op        Unit        Value      Discount
==========================================================
1   Gender       =         NULL        Male       0.07
2   Gender       =         NULL        Female     0.08
3   Age          >=        Year        60         0.02
4   Age          =         Year        18         0.09
5   Age          <=        Month       6          0.04
6   Height       <=        NULL        150        0.03
7   Height       >=        NULL        165        0.06

我正在尝试仅选择与客户数据匹配的记录

DECLARE @Gender varchar(10) = 'Male'
DECLARE @Age int = 70 -- In months

SELECT * 
FROM Rules
WHERE (Field = 'Gender' AND Value = @Gender) OR 
(@Age/12 BETWEEN 
        CASE 
            WHEN Field = 'Age' AND Op IN ('=', '>', '>=')  AND Unit = 'Year' THEN (@Age/12)
            ELSE 0
        END
        AND
        CASE 
            WHEN Field = 'Age' AND Op IN ('=', '<', '<=')  AND Unit = 'Year' THEN (@Age/12)
            ELSE 999
        END
)

但问题在于这个查询我选择了所有规则,而不仅仅是相关的规则。

如何调整它以将选择限制为仅相关记录?

【问题讨论】:

  • 您打算如何输入 3 个月的年龄?由于年龄为int,因此您不能输入0.25 年。年龄是否以月为单位?
  • @OlivierJacot-Descombes 我要将条件拆分为 Years 和 Months 另一个(2 个 case 语句)
  • 我的意思是,@Age 有什么单位?
  • @OlivierJacot-Descombes 只是年份和月份
  • 那么70 是什么意思? 70年70个月7年0个月?

标签: sql-server tsql where-clause


【解决方案1】:

我假设Value 是一个文本列。在比较年龄之前,它必须转换为数字。我在子选择中这样做。

我还假设@Age 以月为单位。因此,如果给出 70 岁的年龄,则必须输入为

DECLARE @Age int = 12 * 70

年龄必须始终以相同的单位给出,因为查询无法确定是否应该将其作为年或月进行比较。例如。如果输入 5,则如果是 5 个月的婴儿,则适用 0.04 的折扣,但如果是 5 岁的孩子,则不适用年龄折扣。

SELECT *
FROM
  (SELECT *, CASE WHEN IsNumeric(Value)=1 THEN CONVERT(int, Value) ELSE 0 END AS IntValue
   FROM Rules
   ) R
WHERE
    (Field = 'Gender' AND @Gender = Value) OR
    (Field = 'Age' AND Op = '>=' AND
        @Age >= IntValue * CASE Unit WHEN 'Year' THEN 12 ELSE 1 END) OR
    (Field = 'Age' AND Op = '=' AND
        @Age = IntValue * CASE Unit WHEN 'Year' THEN 12 ELSE 1 END) OR
    (Field = 'Age' AND Op = '<=' AND
        @Age <= IntValue * CASE Unit WHEN 'Year' THEN 12 ELSE 1 END);

另请注意,我将IntValue 相乘以将年份转换为月份,而不是除以年龄。这更好,因为除法会导致舍入错误。通过乘法,我们保持在整数范围内。

这可以简化,例如通过测试Age的字段名称一次,但我认为如果每个规则都单独翻译,则更容易阅读。

见:http://sqlfiddle.com/#!18/3df02/11/0

【讨论】:

    猜你喜欢
    • 2013-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 2021-10-28
    相关资源
    最近更新 更多