我需要找出某项功能的有效价格

  • 一个功能可以有一个或多个价格规则(规则数<10;通常为<4)
  • 该功能的价格可能取决于订购的其他功能
  • 根据订购的其他功能(低于F2、F3),价格可以降低或提高.
  • 有些功能对F1(低于F6、F8、F9)的价格没有影响.

Sqlfiddle demo with sample records个个

从大海捞针(顺序)来看,每个特征(这里是F1)必须与一个价格规则相匹配.有效价格是功能交叉点最多的价格.

Sample records and tables

这张图显示了价格与不同订单之间的映射.与特性f1相关的价格基于价格规则表中的特性与订单中的特性之间的交集.

pricerules for feature F1 and orders with feature F1

示例

  • F1美元的价格取决于(F1, F2, F3)的功能
  • 特征F1的价格可以通过 Select 在其与草堆(订单)的交集中具有最多元素的F1的价格规则来确定.

本例针对功能F1有三个价格规则和三个不同的订单.

  • 订单1只有F1个与F1的定价规则相匹配;正确的价格是6
  • 订单2在大海捞针中有两个匹配的功能(F1+F2),与F1的价格规则匹配;正确的价格是4
  • 订单3有三个匹配(F1+F2+F3)的F1;正确的价格是2

此查询是我try 连接记录,但存在许多重复项和错误的连接记录

SELECT op.OrderId, op.Id as OrderPositionId, 
       op.FeatureId, f.Featurename, pr.Price 
FROM OrderPositions op 
INNER JOIN FeatureCombinations fc ON op.FeatureId = fc.FeatureId
INNER JOIN Features f on op.FeatureId = f.Id
INNER JOIN PriceRules pr ON fc.PriceRuleId = pr.Id
ORDER BY op.OrderId, op.Id, f.Id;

Sqlfiddle demo with sample records个个

从当前结果来看,带有(X)的所有记录都是错误的

OrderId OrderPositionId FeatureId Featurename Price
401 211 1 F1 6
401 211 x 1 F1 4
401 211 x 1 F1 2
402 221 x 1 F1 6
402 221 1 F1 4
402 221 x 1 F1 2
402 222 x 2 F2 4
402 222 x 2 F2 2
403 231 x 1 F1 6
403 231 x 1 F1 4
403 231 1 F1 2
403 232 x 2 F2 4
403 232 x 2 F2 2
403 233 x 3 F3 2

问题

如何确定某个功能的哪个价格规则最匹配(elements from order ∩ elements from pricerule)?

SQL Statemens用于创建包含记录的表

创建表

CREATE TABLE Features(
  Id    INTEGER PRIMARY KEY, 
  Featurename  TEXT
);
CREATE TABLE PriceRules(
  Id     INTEGER PRIMARY KEY, 
  Price  REAL   
);
CREATE TABLE FeaturesPriceRules(
  FeatureId   INTEGER, 
  PriceRuleId INTEGER,
  FOREIGN KEY(FeatureId) REFERENCES Features(Id),
  FOREIGN KEY(PriceRuleId) REFERENCES PriceRules(Id)
);

CREATE TABLE FeatureCombinations(
  PriceRuleId INTEGER,
  FeatureId   INTEGER,   
  FOREIGN KEY(PriceRuleId) REFERENCES PriceRules(Id),
  FOREIGN KEY(FeatureId) REFERENCES Features(Id)  
);

CREATE TABLE OrderPositions(
  Id INTEGER  PRIMARY KEY, 
  OrderId   INTEGER,   
  FeatureId   INTEGER,     
  FOREIGN KEY(FeatureId) REFERENCES Features(Id)  
);

创建记录


INSERT INTO Features (Id, Featurename)
VALUES (1, 'F1'), (2, 'F2'), (3, 'F3'),
       (4, 'F6'), (5, 'F7'), (6, 'F9'),
       (7, 'E1'), (8, 'ZA2');

INSERT INTO PriceRules (Id, Price)
VALUES (101, '6.00'), (102, '4.00'), (103, '2.00'),
       (105, '24.00'), (106, '22.00');  
    
INSERT INTO FeaturesPriceRules (FeatureId, PriceRuleId)
VALUES (1, 101), (1, 102), (1, 103),(7, 105),(7, 106);  
               
INSERT INTO FeatureCombinations (PriceRuleId, FeatureId)
VALUES (101, 1), (102, 1), (102, 2),
       (103, 1), (103, 2),(103, 3), 
       (105, 7), (106, 7), (106, 8); 
       
INSERT INTO OrderPositions(Id, OrderId, FeatureId)
VALUES (211, 401, 1), (221, 402, 1),(222, 402, 2),
(231, 403, 1),(232, 403, 2),(233, 403, 3);         
   

另请参阅此Sqlfiddle demo with sample records个个

推荐答案

您想要显示所有订单位置.为此,我们将OrderPositions与Feature连接在一起.现在,唯一缺少的是我们可以在相关子查询中获得的价格:

select
  op.orderid,
  op.id as orderpositionid,
  op.featureid,
  f.featurename,
  (...) as price
from orderpositions op
join features f on f.id = op.featureid
order by op.orderid, op.id;

要获得价格有点棘手,因为我们必须查看订单中的所有功能,才能获得涵盖订单中大多数功能的价格规则.这需要聚合与按规则排序要素相关联的功能集.规则中所需的所有功能都必须匹配.匹配规则-如果有多个-必须进行排序,因此我们使用ORDER BY子句:在平局的情况下,我们想要需要最多特征的规则(按降序的特征计数排序),如果我们仍然得到平局,例如具有特征F1、F2、F3的顺序以及[F1,F2]和[F1,F3]上的两个候选规则,该算法将任意挑选其中之一.

这是子查询:我们按规则聚合,并计算该规则中匹配的要素的数量.然后我们按匹配数递减排序.对于平局,我们希望获得需要较少匹配的规则,因此我们也根据总特征计数进行排序.

select pr.price
from featurespricerules fpr
join PriceRules pr on pr.id = fpr.PriceRuleId
join featurecombinations fc on fc.priceruleid = pr.id
left join OrderPositions op2 on op2.orderid = op.orderid
                            and op2.featureid = fc.featureid
where fpr.featureid = op.featureid
group by pr.id
having count(op2.id) = count(*)
order by count(*) desc
limit 1

完整的查询:

select
  op.orderid,
  op.id as orderpositionid,
  op.featureid,
  f.featurename,
  (
     select pr.price
     from featurespricerules fpr
     join PriceRules pr on pr.id = fpr.PriceRuleId
     join featurecombinations fc on fc.priceruleid = pr.id
     left join OrderPositions op2 on op2.orderid = op.orderid
                                 and op2.featureid = fc.featureid
     where fpr.featureid = op.featureid
     group by pr.id
     having count(op2.id) = count(*)
     order by count(*) desc
     limit 1
  ) as price
from orderpositions op
join features f on f.id = op.featureid
order by op.orderid, op.id;

对于你的样本数据,我得到了

OrderId orderpositionid FeatureId Featurename price
401 211 1 F1 6
402 221 1 F1 4
402 222 2 F2 (null)
403 231 1 F1 2
403 232 2 F2 (null)
403 233 3 F3 (null)

您的样本数据不包含F2和F3的价格规则,因此我们不知道它们各自的价格.

演示:http://sqlfiddle.com/#!5/740cf/113

Sql相关问答推荐

UPDATE查询中的乐观锁

如何在SQL Server中拆分包含字符和数字的列?

在SQL查询中使用COALESS

使用左外部联接更正列中第+1行的值时重复

SQL JSON_QUERY 使用列中的值构造 json 路径并接收错误

将 jsonb 数组中的对象取消嵌套到单独的行中

创建具有多个子查询的 SQL 视图

如何计算两个非周期性时间序列+分组的重叠持续时间

基于变量的条件 WHERE 子句

根据不同日期标准分配组的逻辑

使用SQLAlchemy和Postgres数据库创建新行时,为什么我的创建日期比更新日期晚?

比使用NOT EXISTS更高效的SQL删除方法是什么?

如何将输出转换为二维格式?

PostgreSQL如何将Unix纪元时间戳转换为日期时间并进行拼接

PostgreSQL - 从同一张表中获取值

如何在 SQL Server 中将 -13422.8450 舍入到 -13422.84

为什么 Oracle 在一个查询中对同一张表同时执行 TABLE SCAN 和 INDEX UNIQUE SCAN?

按 15 分钟递增计数分组,包括 0 计数

snowflake插入覆盖行为

如何优化sql请求?