php - 在 SQL 中计算级联价格规则

标签 php mysql sql postgresql doctrine

我正在构建一个工具,允许人们将项目发布到类别中。在发布项目之前,需要进行价格计算以确定向发布项目的用户收取的价格。

我想到了使用名为 price_rule 的表来定义规则的概念,它看起来像这样:

+------------ +
| Field       |
--------------+
| id          |
| user        |
| category    |
| price       |
+-------------+

作为一般规则,这个数据库总是有一个后备行。该行用于在没有其他规则与特定上下文匹配的情况下确定价格。那一行是这样的:

+-----------+---------+-------------+-------+
| id        | user    | category    | price |
+-----------+---------+-------------+-------+
| 1         | NULL    | NULL        | 10.00 |
+-----------+---------+-------------+-------+

有了这一行,没有其他行,一篇文章的成本总是 10.00 美元。

现在假设添加了一个额外的行。表格现在看起来像这样:

+-----------+---------+-------------+-------+
| id        | user    | category    | price |
+-----------+---------+-------------+-------+
| 1         | NULL    | NULL        | 10.00 |
+-----------+---------+-------------+-------+
| 2         | Bob     | NULL        | 8.00  |
+-----------+---------+-------------+-------+

添加此规则后,Bob 将为所有类别的每个帖子支付 8.00 美元,其余用户将为所有类别支付 10.00 美元。

如果我们添加更多包含特定用户和特定类别的行:

+-----------+---------+-------------+-------+
| id        | user    | category    | price |
+-----------+---------+-------------+-------+
| 1         | NULL    | NULL        | 10.00 |
+-----------+---------+-------------+-------+
| 2         | Bob     | NULL        | 8.00  |
+-----------+---------+-------------+-------+
| 3         | Bob     | Bicycles    | 9.50  |
+-----------+---------+-------------+-------+
| 4         | Meghan  | Bicycles    | 5.00  |
+-----------+---------+-------------+-------+

当 Bob 在自行车类别中发帖时,他的价格是 9.50 美元。任何其他类别,Bob 将支付 8.00 美元。

Meghan 现在将为自行车类别的帖子支付 5.00 美元,为每个其他类别支付 10.00 美元。

在任何类别(包括自行车)中发帖的所有其他用户都将支付 10.00 美元的默认价格。

在现实世界中,此表可能有数百行,这将允许对发布的价格进行精细控制。

如果您想知道,这个概念背后有商业动机,因为在此系统中发帖的成本并不总是确定的。相反,它基于与发帖用户的业务关系。

当尝试设计一个返回适用于正在发布的帖子的最相关定价规则的查询时,问题就暴露出来了。查询此表时,我可以访问以下信息:用户和类别。我尝试了查询的组合,并阅读了一些 SQL 概念,例如 IFNULLCOALESCE,但我无法确定正确的查询。

另一个问题是,在我们的实际应用程序中,price_rule 表中有一个额外的列来确定价格,但我省略了这个细节以使这个问题中使用的示例更简单。我觉得无论是 2 列还是 3 列用于计算,都可能适用相同的解决方案。

请注意,在应用程序代码中实现了约束,以防止添加重复规则。

我们还使用 Doctrine ORM 和 Doctrine DBAL,因此如果您的查询与查询生成器或 DQL 开箱即用,您的答案将被认为更有值(value)。在 PostgreSQL 或 MySQL 中可用的标准 SQL 解决方案也是可以接受的。

虽然我想尽可能避免这种情况,但一个有效的解决方案可能还包括从 price_rule 表中获取每一行并使用应用程序代码确定适用的规则。如果您的解决方案基于此概念,请包含相关的伪代码。

最佳答案

Postgresql Fiddle

create or replace function price_rule(
    _user varchar(50), _category varchar(50)
) returns setof price_rule as $$

select id, "user", category, price
from (
    select *, 0 as priority
    from price_rule
    where category = _category and "user" = _user

    union

    select *, 1 as priority
    from price_rule
    where "user" = _user and category is null

    union

    select *, 2 as priority
    from price_rule
    where "user" is null and category is null
) s
order by priority
limit 1
;
$$ language sql;

我把上面的查询变成了一个函数只是为了方便测试。但如果您愿意,只需打开它即可。

在 MySQL 中,我不记得如何创建一个函数,所以它是原始的:

MySQL Fiddle

select id, `user`, category, price
from (
    select *, 0 as priority
    from price_rule
    where category = 'Bicycles' and `user` = 'Bob'

    union

    select *, 1 as priority
    from price_rule
    where `user` = 'Bob' and category is null

    union

    select *, 2 as priority
    from price_rule
    where `user` is null and category is null
) s
order by priority
limit 1;

关于php - 在 SQL 中计算级联价格规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25330400/

相关文章:

SQL Server 自动去除尾随空格

MySQL:长时间运行的 LEFT JOIN 查询性能

php - 增量更新数据库字段

php - 观察者可以破坏 Magento 中的事件吗?

mysql - 使用 SQL 插值的 ScalikeJDBC 出现未知 SQL 语法错误

Java MySQL 语法错误

php - 如何使 laravel 多对一(hasMany)关系有效

sql - 在 PostgreSQL 中转换时间戳

PHP:递归获取父级的子级

php - 表锁定以进行读取