简体   繁体   中英

Mysql Create Flexible View from SQL query

I had a lot of attempts now but nothing realy helps. I wannt to create a flexible View(if possible). With the result of 2 tabels. Here is what i wannt :

Table Visitor:

ID      Hash              created
1   sadasdasdasd    2017-02-24 08:31:37
2   123kipdösas3    2017-02-24 08:31:37
3   12oaskdasdap    2017-02-24 08:31:37
4   asdauihsuahs    2017-02-24 08:31:37

Table VisitorData

id  vID   type          value                      created
1   1   First Name      Hans                2017-02-24 09:15:11
2   1   Last Name       Wurst               2017-02-24 09:15:11
3   1   Company         WDHUWDHUGMBGH       2017-02-24 09:15:11
4   1   E-Mail          asddas@asdsd.de     2017-02-24 09:15:11
5   1   Phone           123123              2017-02-24 09:15:11
6   1   Salutation      Mr                  2017-02-24 09:15:11
7   1   Type            qwes                2017-02-24 09:15:11

In the end i wannt my Table(view) to be like:

id  vID  First Name    Last Name      Company       E-Mail               Phone    Salutation   Type                     
1   1       Hans        Wurst        WDHUWDHUGMBGH   asddas@asdsd.de    123123       Mr         qwes     

the fact is that we dont know what can be in the VisitorData.type. so i cant just do

CREATE VIEW DataVisitorView AS
  SELECT DataVisitor.id, DataVisitor.hash, 
    IF(DataVisitorValues.Type='First Name',DataVisitorValues.Value,null) AS First Name,
    IF(DataVisitorValues.Type='Last Name',DataVisitorValues.Value,null) AS Last Name  ,
    IF(DataVisitorValues.Type=' Company ',DataVisitorValues.Value,null) AS Company         ,
    IF(DataVisitorValues.Type='E-Mail',DataVisitorValues.Value,null) AS E-Mail,
    IF(DataVisitorValues.Type='Phone           ',DataVisitorValues.Value,null) AS Phone           ,
    IF(DataVisitorValues.Type='Salutation      ',DataVisitorValues.Value,null) AS Salutation      
 FROM `DataVisitor`
    LEFT JOIN `DataVisitorValues`
      ON `DataVisitor`.`id` = `DataVisitorValues`.`vID`

so i was thinking more about this

CREATE VIEW `DataVisitorView` AS
SELECT
  DataVisitorValues2.typ
FROM (`DataVisitor2`
  LEFT JOIN `DataVisitorValues2`
    ON `DataVisitor2`.`id` = `DataVisitorValues2`.`vID`)
Where `DataVisitor2`.`id` = `DataVisitorValues2`.`vID`

but this it totaly wrong i get a table with

|typ|

First Name
Last Name
Company 
...

Is there any Solution for this? I also used Php for the job but the table but automaticly update himself and a chrone job is nothing that helps here

You cant create dynamic views or views with variables in it. So you need to dynamic query.

Create table/insert data

CREATE TABLE Visitor
    (`ID` INT, `Hash` VARCHAR(12), `created` VARCHAR(19))
;

INSERT INTO Visitor
    (`ID`, `Hash`, `created`)
VALUES
    (1, 'sadasdasdasd', '2017-02-24 08:31:37'),
    (2, '123kipdösas3', '2017-02-24 08:31:37'),
    (3, '12oaskdasdap', '2017-02-24 08:31:37'),
    (4, 'asdauihsuahs', '2017-02-24 08:31:37')
;


CREATE TABLE VisitorData
    (`id` INT, `vID` INT, `type` VARCHAR(10), `value` VARCHAR(15), `created` VARCHAR(19))
;

INSERT INTO VisitorData
    (`id`, `vID`, `type`, `value`, `created`)
VALUES
    (1, 1, 'First Name', 'Hans', '2017-02-24 09:15:11'),
    (2, 1, 'Last Name', 'Wurst', '2017-02-24 09:15:11'),
    (3, 1, 'Company', 'WDHUWDHUGMBGH', '2017-02-24 09:15:11'),
    (4, 1, 'E-Mail', 'asddas@asdsd.de', '2017-02-24 09:15:11'),
    (5, 1, 'Phone', '123123', '2017-02-24 09:15:11'),
    (6, 1, 'Salutation', 'Mr', '2017-02-24 09:15:11'),
    (7, 1, 'Type', 'qwes', '2017-02-24 09:15:11')
;

Query

What you want is a output thats is called a pivot table. This is done with GROUP BY and using the function MAX like this.

SELECT 
   Visitor.id
 , VisitorData.vid
 , MAX(CASE WHEN VisitorData.type = 'First Name' THEN VisitorData.value ELSE NULL END) AS 'First_name'
 , MAX(CASE WHEN VisitorData.type = 'Last Name' THEN VisitorData.value ELSE NULL END) AS 'Last_Name'
 , MAX(CASE WHEN VisitorData.type = 'Company' THEN VisitorData.value ELSE NULL END) AS 'Company'
 , MAX(CASE WHEN VisitorData.type = 'E-Mail' THEN VisitorData.value ELSE NULL END) AS 'E-Mail'
 , MAX(CASE WHEN VisitorData.type = 'Phone' THEN VisitorData.value ELSE NULL END) AS 'Phone'
 , MAX(CASE WHEN VisitorData.type = 'Salutation' THEN VisitorData.value ELSE NULL END) AS 'Salutation'
 , MAX(CASE WHEN VisitorData.type = 'Type' THEN VisitorData.value ELSE NULL END) AS 'Type'
FROM 
 Visitor
INNER JOIN 
 VisitorData
ON
 Visitor.id = VisitorData.vid
GROUP BY 
   Visitor.id
 , VisitorData.vid
ORDER BY 
   Visitor.id
 , VisitorData.vid 

Result

    id     vid  First_name  Last_Name  Company        E-Mail           Phone   Salutation  Type    
------  ------  ----------  ---------  -------------  ---------------  ------  ----------  --------
     1       1  Hans        Wurst      WDHUWDHUGMBGH  asddas@asdsd.de  123123  Mr          qwes    

To make the columns dynamic you can use this.

SET SESSION group_concat_max_len = 1000000 -- enlarge GROUP_CONCAT output to 10 Mb
SET @group_concat_sql = NULL;

# generate all MAX lines 
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'MAX(CASE WHEN VisitorData.type = \'',VisitorData.type,'\' THEN VisitorData.value ELSE NULL END) AS \'',VisitorData.type,'\''      
    )
  )
    INTO @group_concat_sql
FROM
 VisitorData;

# generate complete SQL query
SET @sql = 
CONCAT(
 'SELECT 
     Visitor.id
   , VisitorData.vid
 '
 , ','
 , @group_concat_sql
 , 'FROM 
 Visitor
INNER JOIN 
 VisitorData
ON
 Visitor.id = VisitorData.vid
GROUP BY 
   Visitor.id
 , VisitorData.vid
ORDER BY 
   Visitor.id
 , VisitorData.vid 
'  
); 

# execute SQL query
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

Result

    id     vid  First Name  Last Name  Company        E-Mail           Phone   Salutation  Type    
------  ------  ----------  ---------  -------------  ---------------  ------  ----------  --------
     1       1  Hans        Wurst      WDHUWDHUGMBGH  asddas@asdsd.de  123123  Mr          qwes    

It looks as though you aren't going to have a lot of control over your data. I pretty much agree with @Raymond Nijland approach but I would add some code to bring a degree of control. Start by creating a synonyms table.

drop table if exists synonym_table;
create table synonym_table (ordinalposition int, `type` varchar(10) , synonym varchar(10));
alter table synonym_table
    add key k001(`type`),
    add key k002(synonym);

This will allow you to standardise terms like Company and CO. For example

truncate table visitordata;
INSERT INTO VisitorData
    (`id`, `vID`, `type`, `value`, `created`)
VALUES
    (1, 1, 'First Name', 'Hans', '2017-02-24 09:15:11'),
    (2, 1, 'Last Name', 'Wurst', '2017-02-24 09:15:11'),
    (3, 1, 'Company', 'WDHUWDHUGMBGH', '2017-02-24 09:15:11'),
    (4, 1, 'E-Mail', 'asddas@asdsd.de', '2017-02-24 09:15:11'),
    (5, 1, 'Phone', '123123', '2017-02-24 09:15:11'),
    (6, 1, 'Salutation', 'Mr', '2017-02-24 09:15:11'),
    (7, 1, 'Type', 'qwes', '2017-02-24 09:15:11'),
    (8, 2, 'FName', 'Hans', '2017-02-24 09:15:11'),
    (9, 2, 'Last Name', 'Wurst', '2017-02-24 09:15:11'),
    (10, 2, 'Co.', 'WDHUWDHUGMBGH', '2017-02-24 09:15:11')

insert into synonym_table (`type`,synonym) 
select distinct `type`,`type` from visitordata v order by id
on duplicate key update `type` = v.`type`;

Note the synonyms default to the type and the on duplicate key clause ensures uniqueness Now update known synonyms - note you will have to do this as often as necessary

update synonym_table
        set synonym = 'First Name' where `type` in('fname' , 'FirstName');

update synonym_table
    set synonym = 'Company' where `type` in('Co.' , 'Business', 'Agency');

MariaDB [sandbox]> select * from synonym_table;
+--------------+------------+------------+
| ordinalvalue | type       | synonym    |
+--------------+------------+------------+
|         NULL | First Name | First Name |
|         NULL | Last Name  | Last Name  |
|         NULL | Company    | Company    |
|         NULL | E-Mail     | E-Mail     |
|         NULL | Phone      | Phone      |
|         NULL | Salutation | Salutation |
|         NULL | Type       | Type       |
|         NULL | FName      | First Name |
|         NULL | Co.        | Company    |
+--------------+------------+------------+

Update the ordinalposition to control the order of the column headers. Now adapt the code from raymond to use the synonym_table

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM