简体   繁体   English

MySQL动态创建行中的列

[英]MySQL create columns out of rows on the fly

My issue is that I have a table apidata that holds multiple rows of data for each domain. 我的问题是我有一个表apidata ,其中包含每个域的多行数据。 So when I query apidata I naturally get multiple rows as a result. 因此,当我查询apidata我自然会得到多行结果。 Is there any way to turn those rows into columns? 有什么办法可以将这些行转换为列? I ask because I'm already using a query to pull the domain data (page title, URL, top level domain, ip address etc) and I need to add the api data with it. 我问是因为我已经在使用查询来提取域数据(页面标题,URL,顶级域,ip地址等),并且我需要在其中添加api数据。 I believe I have to do this in two queries but I would love to at least have one row per domain to make the query and loop as fast a possible. 我相信我必须在两个查询中执行此操作,但我希望每个域至少有一行,以使查询和循环尽可能快。

So the question is, can I create columns out of rows on the fly? 所以问题是,我可以动态地在行之外创建列吗?

Heres a SQL Fiddle => http://sqlfiddle.com/#!2/8e408/4 继承人SQL小提琴=> http://sqlfiddle.com/#!2/8e408/4

(Note, I didnt put the whole database in the fiddle just the tables that effect the query. If you think somethings missing that you need, let me know.) (请注意,我没有将整个数据库放在只会影响查询的表的位置。如果您认为需要缺少某些内容,请告诉我。)

Tool_Runs (id_sha is the main lookup value for tool runs) Tool_Runs (id_sha是工具运行的主要查找值)

| ID | ID_SHA                                   |
+----+------------------------------------------+
| 1  | 68300DF58B2A8A6E098CB0B3D1A9AE80BBE5897A |

Domains (Run_id is FK to tool_runs.id) (Run_id是tool_runs.id的FK)

| ID | RUN_ID |
+----+--------+
| 1  |   1    |

API Data API数据

| ID | DOMAIN_ID | EXPORT_COLUMN    | COLUMN_TITLE      | VALUE |
+----+-----------+------------------+-------------------+-------+
| 1  | 1         | referringDomains | Referring Domains | 10    |
+----+-----------+------------------+-------------------+-------+
| 2  | 1         | linkCount        | Backlink Count    | 55    |

Heres my query now: 现在是我的查询:

SELECT a.domain_id, a.export_column, a.column_title, a.value 
FROM apidata AS a WHERE domain_id IN
(
  SELECT d.id FROM tool_runs AS t
  JOIN domains AS d ON d.run_id = t.id
  WHERE id_sha = '68300DF58B2A8A6E098CB0B3D1A9AE80BBE5897A'
)
ORDER BY a.domain_id

And what I get is: 我得到的是:

| DOMAIN_ID | EXPORT_COLUMN    | COLUMN_TITLE      | VALUE    |
+-----------+------------------+-------------------+----------+
| 1         | referringDomains | Referring Domains | 10       |
+-----------+------------------+-------------------+----------+
| 1         | linkCount        | Backlink Count    | 55       |

But what I want is 但是我想要的是

| DOMAIN_ID | referringDomains | referringDomains_TITLE | linkCount | linkCount_TITLE |
+-----------+------------------+------------------------+-----------+-----------------+
| 1         | 10               | Referring Domains      | 55        | Backlink Count  |

What you are trying to is to pivot the table rows into columns. 您要尝试的是将表行透视成列。 Unfortunately MySQL doesn't have a native pivot table operator, but you can use the CASE expression to do so: 不幸的是,MySQL没有本地数据透视表运算符,但是您可以使用CASE表达式来实现:

SELECT 
  a.Domain_id,
  MAX(CASE WHEN a.export_column = 'referringDomains' THEN a.value END) AS referringDomains,
  MAX(CASE WHEN a.export_column = 'referringDomains' THEN a.column_title END) AS referringDomains_TITLE,
  MAX(CASE WHEN a.export_column = 'linkCount' THEN a.value END) AS linkCount,
  MAX(CASE WHEN a.export_column = 'linkCount' THEN a.column_title END) AS linkCount_TITLE
FROM apidata AS a 
WHERE domain_id IN
(
  SELECT d.id FROM tool_runs AS t
  JOIN domains AS d ON d.run_id = t.id
  WHERE id_sha = '68300DF58B2A8A6E098CB0B3D1A9AE80BBE5897A'
) 
GROUP BY a.domain_id;

Note that: If you want to do so for all the values in the export_column , you have to write a CASE expression for each value. 请注意:如果要对export_column中的所有值都这样做,则必须为每个值编写一个CASE表达式。 But you can do that using dynamic sql like this: 但是您可以使用动态sql来做到这一点,如下所示:

SET @ecvalues = NULL;
SET @ectitles = NULL;
SET @sql = NULL;

SELECT
  GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(a.export_column = ''',
      a.export_column, ''', a.value , NULL)) AS ', '''', a.export_column , '''')
  ) INTO @ecvalues
FROM apidata a;


SELECT
  GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(a.export_column = ''',
      a.export_column, ''', column_title , NULL)) AS ', '''', CONCAT(a.export_column , '_Titles'), '''')
  ) INTO @ectitles
FROM apidata a;


SET @sql = CONCAT('SELECT 
  a.Domain_id, ', @ectitles , ',', @ecvalues, '
    FROM apidata AS a 
WHERE domain_id IN
(
  SELECT d.id FROM tool_runs AS t
  JOIN domains AS d ON d.run_id = t.id
  WHERE id_sha = ''68300DF58B2A8A6E098CB0B3D1A9AE80BBE5897A''
) 
GROUP BY a.domain_id;');

prepare stmt 
FROM @sql;

execute stmt;

You can put that query inside a stored procedure. 您可以将该查询放入存储过程中。

Just as a complement to the @MahmoudGamal answer you should know that for any new registry ( EXPORT_COLUMN ) you will have to add a new case statement. 作为对@MahmoudGamal答案的补充,您应该知道,对于任何新注册表( EXPORT_COLUMN ),您都必须添加新的case语句。

So in order to do it dynamic you can create a procedure as described on this post at dba.stackexchange. 因此,为了使其动态化,您可以按照dba.stackexchange上的这篇文章中所述创建一个过程。

How to transpose/convert rows as columns in mysql 如何在MySQL中将行转置/转换为列

It shows how to do it dynamically. 它显示了如何动态执行此操作。

If you want columns, go ahead and pivot as the example above. 如果要使用列,请继续进行如上示例的透视图。 If you only want a single string, for some reporting reason, go ahead and do: 如果出于某些报告原因,只想要一个字符串,请继续执行以下操作:

SELECT group_concat(CONCAT_WS(' ',a.domain_id, a.value, a.column_title, a.export_column, 'next row string separator'))
FROM apidata AS a WHERE domain_id IN
(
  SELECT d.id FROM tool_runs AS t
  JOIN domains AS d ON d.run_id = t.id
  WHERE id_sha = '68300DF58B2A8A6E098CB0B3D1A9AE80BBE5897A'
)
ORDER BY a.domain_id

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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