不同的价格要求取决于价格货币

时间:2017-07-27 07:28:41

标签: mysql

我有一个包含以下数据的元表:

+----+------------+-----------+------------+
| id | product_id | meta_key  | meta_value |
+----+------------+-----------+------------+
|  1 |          1 | currency  | USD        |
|  2 |          1 | price     | 1100       |
|  3 |          2 | currency  | PLN        |
|  4 |          2 | price     | 1300       |
|  5 |          3 | currency  | USD        |
|  6 |          3 | price     | 1200       |
| 11 |          1 | available | 1          |
| 12 |          2 | available | 1          |
| 13 |          3 | available | 0          |
+----+------------+-----------+------------+

现在,如果产品可用且价格高于1000,我想获取product_id,可以通过以下方式获取:

SELECT product_id
FROM meta
WHERE meta_key IN ("price", "available") 
GROUP BY product_id 
HAVING 1=1  
    AND SUM(meta_key = "price" AND CAST(meta_value AS DECIMAL(10,2))>=1000) > 0
    AND SUM(meta_key = "available" AND meta_value=1) > 0

下一步是检查产品货币,如果我想获取价格高于1000美元的产品,那么不应该返回product_id = 2。 USD / PLN的转换率约为3.63,因此1300PLN约为357.98美元。

有没有办法检查产品货币然后指定不同的价格要求?如果货币是美元,那么该值应该高于' 1000'如果货币是“PLN'然后价值应高于' 3630'

4 个答案:

答案 0 :(得分:1)

您可以使用条件聚合

SELECT product_id,
       COUNT(CASE 
                WHEN meta_key = 'currency' AND meta_value= 'USD' > 0  THEN 1 
             END) AS USD,
       COUNT(CASE 
                WHEN meta_key = 'currency' AND meta_value= 'PLN' > 0  THEN 1 
             END) AS PLN,
       SUM(CASE 
              WHEN meta_key = 'price' THEN CAST(meta_value AS DECIMAL(10,2)) ELSE 0 
           END) AS price,
       COUNT(CASE WHEN meta_key = 'available' AND meta_value=1 THEN 1 END) AS available
FROM meta
WHERE meta_key IN ('price', 'available', 'currency') 
GROUP BY product_id;

以创建以下输出:

product_id  USD PLN price   available
-------------------------------------
1           1   0   1100,00 1
2           0   1   1300,00 1
3           1   0   1200,00 0

现在,您可以轻松查询上面派生的表格以获得所需的结果:

SELECT product_id
FROM (
   ... above query here ...
) AS t
WHERE available > 0 AND (USD = 1 AND price > 1000   
                        OR
                        PLN = 1 AND price > 1000*3.63); 

<强>输出:

product_id
----------
1

Demo here

答案 1 :(得分:0)

如果你以不同的方式布置你的表,那么这个请求是可能的,也可以更高效地完成(如果你的表非常大)。

不使用元表存储数据,而是使用普通表。这样做会创建inner platform effect,你想要避免的事情(你在SQL表中模拟SQL)。

此外,当供应商想要根据国家/地区应用价格歧视,或者想要确保实际价格数量是客户期望的价格时,存在明显的问题:无法以相同产品的多种货币存储价格,示例359而不是358,两件事情恰好相当普遍。

创建此表并使用产品定价填充它:

+----+------------+----------+-------+
| id | product_id | currency | price |
+----+------------+----------+-------+
|  1 |          1 | USD      |   350 |
|  2 |          2 | USD      |   200 |
|  3 |          3 | PLN      |   800 |
+----+------------+----------+-------+

执行此操作的示例方法如下:

INSERT INTO `priceTable` (product_id, currency, price) 
SELECT product_id, meta_value, 0 FROM myTable 
WHERE meta_key = 'currency';

UPDATE `priceTable` SET `price` = (SELECT `meta_value` FROM `myTable` 
WHERE `meta_key` = 'price' AND `myTable`.`product_id` = `priceTable`.`product_id`);

接下来,对于表中的每个唯一产品ID,检查是否存在“USD”行。如果没有,则使用其他货币获取行(我不知道您的数据中是否有超过2种货币),使用美元货币创建一个新行。

E.g。假设每个product_id只有一行具有唯一货币,并且该货币是USD或PLN,这两个查询就可以完成这项工作(使用后端语言为每个选中的循环传输变量)行。):

SELECT `product_id`, 'USD', ROUND(`price` / 3.63, 0)
FROM `priceTable` WHERE `currency` = 'PLN';

INSERT INTO `priceTable` (`product_id`, `currency`, `price`)
VALUES (:product_id, :currency, :price);

您需要使用2个单独的查询,因为SELECTINSERT都引用同一个表。使用第二个临时表也是一种解决方案。

到目前为止,您的问题已经简化为:

SELECT `product_id` FROM `priceTable` WHERE `currency` = 'USD' AND price > 1000;

答案 2 :(得分:0)

Giorgos Betsos的解决方案是正确的。但是,作为一种更通用的解决方案,如果您以非EAV形式写出数据,我想您可能会想出如何回答您可能为这些问题提出的任何进一步的问题。

调整GB的小提琴(并从模型中排除冗余信息)......

drop table if exists meta;

CREATE TABLE meta
    (product_id int, meta_key varchar(12), meta_value varchar(12), PRIMARY KEY(product_id,meta_key))
;

INSERT INTO meta
    (product_id,meta_key,meta_value)
VALUES
    (1, 'currency', 'USD'),
    (1, 'price', '1100'),
    (2, 'currency', 'PLN'),
    (2, 'price', '1300'),
    (3, 'currency', 'USD'),
    (3, 'price', '1200'),
    (1, 'available', '1'),
    (2, 'available', '1'),
    (3, 'available', '0')
;

SELECT product_id 
     , MAX(CASE WHEN meta_key = 'currency' THEN meta_value END) currency
     , MAX(CASE WHEN meta_key = 'price' THEN meta_value END) price
     , MAX(CASE WHEN meta_key = 'available' THEN meta_value END) available
  FROM meta
 GROUP 
    BY product_id;

product_id currency price available
         1 USD       1100         1
         2 PLN       1300         1
         3 USD       1200         0

http://rextester.com/JWW92514

最后,当使用EAV模型时,我总是希望根据数据类型将不同的属性分配给不同的表。因此,您通常会有一个整数类型属性表,一个小数表,一个日期时间表和一个字符串表。

答案 3 :(得分:0)

感谢您的回复。

我最终得到了以下解决方案,我有其他货币表;

+----+------+----------------+
| id | code | conversion_usd |
+----+------+----------------+
|  1 | USD  |       1.000000 |
|  2 | PLN  |       3.650000 |
+----+------+----------------+

现在查询:

SELECT product_id
FROM meta
WHERE product_id IN (
    SELECT price.product_id
    FROM meta AS price
    JOIN meta AS currency ON(price.product_id=currency.product_id AND currency.meta_key='currency')
    JOIN currencies ON(currencies.code=currency.meta_value)
    WHERE
    price.meta_key='price'
    AND price.meta_value/currencies.conversion_usd>1000
)
AND meta_key IN ("available") 
GROUP BY product_id 
HAVING 1=1     
    AND SUM(meta_key = "available" AND meta_value=1) > 0

这样我就不必使用CASE功能,它支持任意数量的货币。