Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/69.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何在表格中获得满足不同标准的产品和价格列表_Mysql_Sql - Fatal编程技术网

Mysql 如何在表格中获得满足不同标准的产品和价格列表

Mysql 如何在表格中获得满足不同标准的产品和价格列表,mysql,sql,Mysql,Sql,我有一个定价表如下: 定价表 我需要找到合同ID列表和特定年龄组的ID(1岁、2岁或3岁)。对于儿童来说,年龄从-到也需要考虑 下面的查询1个成人、2个2&4岁的儿童和1个老年人似乎正在工作,但只返回与年龄组1匹配的ID SELECT contractId,id FROM tbl_contract_price cp1 WHERE contractId IN (SELECT contractId FROM tbl_contract_price cp2 WHERE contractId IN

我有一个定价表如下:

定价表

我需要找到合同ID列表和特定年龄组的ID(1岁、2岁或3岁)。对于儿童来说,年龄从-到也需要考虑

下面的查询1个成人、2个2&4岁的儿童和1个老年人似乎正在工作,但只返回与年龄组1匹配的ID

SELECT contractId,id 
FROM tbl_contract_price cp1 
WHERE contractId IN 
(SELECT contractId FROM tbl_contract_price cp2 
WHERE contractId IN 
(SELECT contractId FROM tbl_contract_price cp3 
WHERE cp1.ageGroup = 1 AND (cp2.ageGroup = 2 AND cp2.ageFrom <= 2 AND 2 <= cp2.ageTo OR cp2.ageGroup = 2 AND cp2.ageFrom <= 4 AND 4 <= cp2.ageTo ) AND cp3.ageGroup = 3))

有什么我遗漏的吗?

基于一些假设,我创建了以下内容来帮助您开始。请注意,您需要加强您的数据完整性,即确保每个产品的所有可能年龄都包含在价格中,等等

CREATE TABLE Pricing (
  ID int not null,
  productId int not null,
  ContractId int not null,
  ageGroup int not null,
  ageFrom int not null,
  ageTo int not null,
  sellingPrice int not null,
  PRIMARY KEY (ID)
);

INSERT INTO Pricing (ID, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (1, 1, 1, 1, 0, 2, 0);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (2, 1, 1, 1, 3, 13, 20);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (3, 1, 1, 2, 18, 55, 80);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (4, 1, 1, 3, 56, 119, 60);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (5, 1, 2, 1, 3, 13, 0);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (6, 1, 2, 2, 18, 55, 85);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (7, 2, 2, 3, 55, 119, 90);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (8, 2, 2, 2, 18, 55, 90);

CREATE TABLE ValidDates (
  ID int not null,
  priceId int not null,
  fromDate date not null,
  toDate date not null,
  PRIMARY KEY (ID)
 );

 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (1, 1, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (2, 2, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (3, 2, '2018-07-01', '2018-07-31');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (4, 3, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (5, 3, '2018-07-01', '2018-07-31');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (6, 4, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (7, 5, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (8, 5, '2018-07-01', '2018-07-31');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (9, 6, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (10, 6, '2018-07-01', '2018-07-31');

 CREATE TABLE Products (
   ID int not null,
   PRIMARY KEY (ID)
 );

CREATE TABLE Quotes (
  ID int not null,
  age int
);

INSERT INTO Quotes (Id, age) VALUES (1, 70);
INSERT INTO Quotes (Id, age) VALUES (1, 25);
INSERT INTO Quotes (Id, age) VALUES (1, 1);
INSERT INTO Quotes (Id, age) VALUES (1, 4); 
我建议您使用一个临时报价表,以便在输入的数量上有更多的灵活性。您可以看到下面的数据示例。或者,更好的方法是在业务逻辑层中处理该逻辑

如果两个合同产生相同的价格,则需要应用任何平局断路器逻辑,等等

CREATE TABLE Pricing (
  ID int not null,
  productId int not null,
  ContractId int not null,
  ageGroup int not null,
  ageFrom int not null,
  ageTo int not null,
  sellingPrice int not null,
  PRIMARY KEY (ID)
);

INSERT INTO Pricing (ID, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (1, 1, 1, 1, 0, 2, 0);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (2, 1, 1, 1, 3, 13, 20);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (3, 1, 1, 2, 18, 55, 80);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (4, 1, 1, 3, 56, 119, 60);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (5, 1, 2, 1, 3, 13, 0);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (6, 1, 2, 2, 18, 55, 85);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (7, 2, 2, 3, 55, 119, 90);
INSERT INTO Pricing (id, productId, ContractId, ageGroup, ageFrom, ageTo, sellingPrice) Values (8, 2, 2, 2, 18, 55, 90);

CREATE TABLE ValidDates (
  ID int not null,
  priceId int not null,
  fromDate date not null,
  toDate date not null,
  PRIMARY KEY (ID)
 );

 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (1, 1, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (2, 2, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (3, 2, '2018-07-01', '2018-07-31');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (4, 3, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (5, 3, '2018-07-01', '2018-07-31');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (6, 4, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (7, 5, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (8, 5, '2018-07-01', '2018-07-31');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (9, 6, '2018-06-01', '2018-06-30');
 INSERT INTO ValidDates (id, priceId, fromDate, toDate) VALUES  (10, 6, '2018-07-01', '2018-07-31');

 CREATE TABLE Products (
   ID int not null,
   PRIMARY KEY (ID)
 );

CREATE TABLE Quotes (
  ID int not null,
  age int
);

INSERT INTO Quotes (Id, age) VALUES (1, 70);
INSERT INTO Quotes (Id, age) VALUES (1, 25);
INSERT INTO Quotes (Id, age) VALUES (1, 1);
INSERT INTO Quotes (Id, age) VALUES (1, 4); 
然后,您可以使用以下查询根据产品id、所选日期和报价id(包含特定报价的所有期限)计算您的总价

场景:游览日期=2018年6月22日;产品=1,报价=1,年龄=1,4,25,70

SELECT @tourdate := '2018-06-22', @productid := 1, @quoteid := 1;
显示如何检索相关信息的第一个查询

SELECT productid, contractId, ageGroup, ageFrom, ageTo,
SUM(CASE WHEN age BETWEEN ageFrom AND ageTo THEN 1 ELSE 0 END) AS PAXCount, sellingPrice
FROM ValidDates
LEFT JOIN Pricing
  ON priceId = Pricing.ID
    LEFT JOIN Products
      ON productId = Products.ID
        LEFT JOIN Quotes
          ON Quotes.ID = @quoteid
WHERE (@tourdate BETWEEN fromDate AND toDate) AND productid = @productid
GROUP BY productid, contractid, ageGroup, ageFrom, ageTo, sellingPrice;
第二个查询是在第一个查询的基础上构建的,它聚合了总数,这样您就有了排名的总成本

SELECT contractId, SUM(sellingPrice * PAXCount) FROM (
SELECT productid, contractId, ageGroup,
SUM(CASE WHEN age BETWEEN ageFrom AND ageTo THEN 1 ELSE 0 END) AS PAXCount, sellingPrice
FROM ValidDates
LEFT JOIN Pricing
  ON priceId = Pricing.ID
    LEFT JOIN Products
      ON productId = Products.ID
        LEFT JOIN Quotes
          ON Quotes.ID = @quoteid
WHERE (@tourdate BETWEEN fromDate AND toDate) AND productid = @productid
GROUP BY productid, contractid, ageGroup, sellingPrice) P
GROUP BY contractid
ORDER BY SUM(sellingPrice * PAXCount)
#LIMIT 1;
您可以取消对Limit 1的注释,以获得最便宜的包,但您需要了解该限制 您需要确保您的数据完整性得到加强,即,对于每个产品和日期范围,所有可能的年龄都需要 请注意,由于合同id 2未涵盖0岁的儿童和70岁的老年人,因此85美元的总额具有误导性。如果输入计数为4,您可以添加逻辑来检查合同是否可以满足所有年龄段的要求,检查合同是否确实包含四个人,等等

您可能需要根据需要清理引号表。这肯定不是最有效的方法,但它应该根据您的需求工作

例如,将查询更改为以下内容:

SELECT @PAXCount := COUNT(*) FROM Quotes WHERE id = @quoteid;
或者,您也可以很容易地从应用程序中传递它。 然后,检查以确保计数匹配

SELECT contractId, SUM(sellingPrice * PAXCount) AS TotalPrice, SUM(PAXCount) AS TotalPAXCOUNT
FROM (
  SELECT productid, contractId, ageGroup,
  SUM(CASE WHEN age BETWEEN ageFrom AND ageTo THEN 1 ELSE 0 END) AS PAXCount, sellingPrice
  FROM ValidDates
  LEFT JOIN Pricing
    ON priceId = Pricing.ID
      LEFT JOIN Products
        ON productId = Products.ID
          LEFT JOIN Quotes
            ON Quotes.ID = @quoteid
  WHERE (@tourdate BETWEEN fromDate AND toDate) AND productid = @productid 
  GROUP BY productid, contractid, ageGroup, sellingPrice) P
GROUP BY contractid
HAVING @PAXCount = SUM(PAXCount)
ORDER BY SUM(sellingPrice * PAXCount)
#LIMIT 1;
这样,只会显示覆盖所有乘客的合同id


您的输入选择标准和预期输出是什么?您提到了验证日期,但我怎么知道哪些日期在您的范围内,所以我假设日期是输入的一部分,以及产品id?您能提到所需的输出吗?@作者对此表示抱歉。刚刚用更多信息编辑了主要帖子。请看这是否足够好。谢谢你们。@GarimaGupta对那个家伙很抱歉。刚刚用更多信息编辑了主要帖子。请看这是否足够好。谢谢。如何将这三个表链接在一起?似乎没有一个通用的键,所以我可以判断哪个价格从哪个日期到哪个日期是有效的。定价表没有有效日期FK等。谢谢。客户已经提出了一些小的修改,并正在进行中。我相信这会对我有很大帮助。我还想知道,当有许多并发查询时,这样一个临时表是否会影响数据库性能?我同意你的担忧。这不是一个临时表,而是一个事务表,但这是绕过数据结构和您的需求所需要的一种技巧。这就是为什么您可能应该考虑更新数据模式,使用适当的缓存,并让业务层为您进行计算。在应用程序中提取相关的定价信息,根据需要缓存并计算价格。