Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/55.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,我有两个数据库表customers,其中包含关于采用如下方案的客户的数据: mysql> SELECT * FROM customers; customer_id created_at partner_id 1 "2019-08-20 09:17:58" cats 2 "2019-09-12 11:46:37" dogs 客户事实以事实名称和相应事实值的形式保存客户事实 我想创建一个透视表,每一行中都有一个客户,

我有两个数据库表customers,其中包含关于采用如下方案的客户的数据:

mysql> SELECT * FROM customers;

customer_id created_at              partner_id
1           "2019-08-20 09:17:58"   cats
2           "2019-09-12 11:46:37"   dogs
客户事实以事实名称和相应事实值的形式保存客户事实

我想创建一个透视表,每一行中都有一个客户,每个客户的事实都作为一个单独的列。大概是这样的:

mysql> SELECT * FROM pivot_table;

customer_id created_at              partner_id  name    city    surname
1           "2019-08-20 09:17:58"   cats        Milton  Milan   
2           "2019-09-12 11:46:37"   dogs        Orlando         Bloom
我找到了一个脚本,可以创建这样的表:

SET @sql = '';
SELECT
    @sql := CONCAT(@sql,if(@sql='','',', '),temp.output)
FROM
(
    SELECT
      DISTINCT
        CONCAT(
         'MAX(IF(cf.fact_name = ''',
          fact_name,
          ''', cf.fact_value, NULL)) AS ''',
          fact_name,
          ''''
        ) as output
    FROM
        customers_facts
) as temp;
SET @sql = CONCAT('SELECT c.customer_id, c.created_at, c.partner_id, ', @sql, ' 
                   FROM customers c
                   LEFT JOIN customers_facts AS cf 
                   ON cf.customer_id = c.customer_id
                   GROUP BY c.customer_id, c.created_at, c.partner_id');
但我有一个问题是如何做到这一点:

a我将能够查询数据透视表

b当我在这两个原始表中添加一个新条目/更新一个旧条目时,透视表将被更新


如何解决?有可能吗?

考虑以下几点:

DROP TABLE IF EXISTS customers;

CREATE TABLE customers
(customer_id SERIAL PRIMARY KEY
,created_at DATETIME NOT NULL
,partner_id INT NOT NULL
);

INSERT INTO customers VALUES
(1,"2019-08-20 09:17:58",108),
(2,"2019-09-12 11:46:37",110);

DROP TABLE IF EXISTS customers_facts ;

CREATE TABLE customers_facts 
(customer_id INT NOT NULL
,fact_name  VARCHAR(20) NOT NULL
,fact_value VARCHaR(20) NOT NULL
,PRIMARY KEY(customer_id,fact_name)
);

INSERT INTO customers_facts VALUES
(1,'name','Milton'),
(1,'city','Milan'),
(2,'surname','Bloom'),
(2,'name','Orlando');
现在我们可以按照您描述的方式创建视图

DROP VIEW IF EXISTS my_pivot;

CREATE VIEW my_pivot AS
SELECT c.customer_id
     , c.created_at
     , c.partner_id
     , MAX(CASE WHEN fact_name = 'name' THEN fact_value END) name
     , MAX(CASE WHEN fact_name = 'surname' THEN fact_value END) surname
     , MAX(CASE WHEN fact_name = 'city' THEN fact_value END) city
  FROM customers c
  LEFT 
  JOIN customers_facts f
    ON f.customer_id = c.customer_id
 GROUP
    BY c.customer_id;
我们可以通过一个简单的查询来查询这个视图,例如,从my_pivot中选择customer_id,其中name='Milton',但是,这不能使用索引,因此效率不高

此外,由于我们创建视图的方式,它无法更新

UPDATE my_pivot SET name = 'Leonardo' WHERE customer_id = 1;
ERROR 1288 (HY000): The target table my_pivot of the UPDATE is not updatable
DROP VIEW IF EXISTS my_pivot;

CREATE VIEW my_pivot AS
SELECT c.customer_id
     , c.created_at
     , c.partner_id
     , name.fact_value name
     , surname.fact_value surname
     , city.fact_value city
  FROM customers c
  LEFT 
  JOIN customers_facts name
    ON name.customer_id = c.customer_id 
   AND name.fact_name = 'name'
  LEFT
  JOIN customers_facts surname
    ON surname.customer_id = c.customer_id 
   AND surname.fact_name = 'surname'
  LEFT
  JOIN customers_facts city
    ON city.customer_id = c.customer_id 
   AND city.fact_name = 'city';

UPDATE my_pivot SET name = 'Leonardo' WHERE customer_id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

SELECT * FROM customers_facts;
+-------------+-----------+------------+
| customer_id | fact_name | fact_value |
+-------------+-----------+------------+
|           1 | city      | Milan      |
|           1 | name      | Leonardo   |
|           2 | name      | Orlando    |
|           2 | surname   | Bloom      |
+-------------+-----------+------------+
然而,如果我们创建的视图略有不同,那么它可以被更新

UPDATE my_pivot SET name = 'Leonardo' WHERE customer_id = 1;
ERROR 1288 (HY000): The target table my_pivot of the UPDATE is not updatable
DROP VIEW IF EXISTS my_pivot;

CREATE VIEW my_pivot AS
SELECT c.customer_id
     , c.created_at
     , c.partner_id
     , name.fact_value name
     , surname.fact_value surname
     , city.fact_value city
  FROM customers c
  LEFT 
  JOIN customers_facts name
    ON name.customer_id = c.customer_id 
   AND name.fact_name = 'name'
  LEFT
  JOIN customers_facts surname
    ON surname.customer_id = c.customer_id 
   AND surname.fact_name = 'surname'
  LEFT
  JOIN customers_facts city
    ON city.customer_id = c.customer_id 
   AND city.fact_name = 'city';

UPDATE my_pivot SET name = 'Leonardo' WHERE customer_id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

SELECT * FROM customers_facts;
+-------------+-----------+------------+
| customer_id | fact_name | fact_value |
+-------------+-----------+------------+
|           1 | city      | Milan      |
|           1 | name      | Leonardo   |
|           2 | name      | Orlando    |
|           2 | surname   | Bloom      |
+-------------+-----------+------------+
…但这仍然不能使用索引

编辑:要回答问题下方评论中提出的问题,您可以

SELECT customer_id 
  FROM customers_facts 
 WHERE 
     ( fact_name,fact_value ) IN (('name','Orlando'),('surname','Bloom')) 
 GROUP 
    BY customer_id 
HAVING COUNT(*) = 2;
…虽然我认为MySQL在这种情况下不能使用索引,所以使用正手版本可能更好

SELECT customer_id 
  FROM customers_facts 
 WHERE 
     ( fact_name = 'name'
   AND fact_value = 'Orlando'
     )
    OR 
     ( fact_name = 'surname'
   AND fact_value = 'Bloom'
     )
 GROUP 
    BY customer_id HAVING COUNT(*) = 2;

这是一个相当低效的野心。像SELECT STUF FROM table WHERE fact_name='name'这样的查询总是会超出您的想象。好吧,但当我需要找到一个名为==John和姓氏==Smith的客户id时会发生什么情况?其中姓名和姓氏是事实名称-这是我想要解决的情况-使用什么查询?例如,从客户事实中选择客户id其中,“姓名”、“奥兰多”、“姓氏”、“布鲁姆”组中的事实名称、事实值(按客户id,计数*=2);当我向customers\u facts添加一个新的事实名称时,情况又如何呢?例如:在customers\u facts值中插入1、'sex'、'Male'-它会在视图中创建一个新的列sex吗?不会。除非连续动态地重新创建视图,否则不会。正如我所说,最好在应用程序代码中处理显示问题。