将行值转换为列,并计算所有可能值 mysql 的重复次数

Posted

技术标签:

【中文标题】将行值转换为列,并计算所有可能值 mysql 的重复次数【英文标题】:turn rows values to columns , and count repetitions for all possible values mysql 【发布时间】:2017-06-22 04:01:58 【问题描述】:

我有一个表(来自日志文件),其中包含电子邮件和其他三个列,其中包含该用户与系统交互的状态,电子邮件(用户)可能有 100 或 1000 个条目,每个条目包含这三个值的组合,对于同一封电子邮件和其他电子邮件,这可能会不断重复。 看起来像这样:

+---------+---------+---------+-----+
| email |  val1   |  val2 |  val3   |
+---------+---------+---------+-----+
|jal@h  |  cast   | core  |   cam   |
|hal@b  |little ja| qar   |  ja sa  |
|bam@t  |  cast   | core  |   cam   |
|jal@h  |little ja| qar   |  jaja   | 
+---------+---------+---------+-----+

因此,电子邮件重复,所有值重复,每列有 40 多个可能的值,所有字符串。所以我想对不同的电子邮件进行排序,然后将所有可能的值作为列名,并在其下计算特定电子邮件的重复值的数量,如下所示:

+-------+--------+--------+------+----------+-----+--------+-------+
| email | cast   |   core |  cam | little ja| qar |  ja sa | blabla |
+-------+--------+--------+------+----------+-----+--------+--------|
|jal@h  |  55    |   2    | 44   |   244    | 1   | 200    | 12     |
|hal@b  |  900   |  513   | 101  |   146    |  2  |  733   | 833    |
|bam@t  |  1231  |   33   | 433  |   411    | 933 | 833    | 53     |
+-------+--------+--------+------+----------+-----+--------+---------

我尝试了 mysql,但我设法计算了每封电子邮件的某个值的总出现次数,但没有计算每列中所有可能的值:

SELECT 
  distinct email,

  count(val1) as "cast"
FROM table1
where val1 = 'cast'
group by email

这个查询显然没有这样做,因为它只输出第一列“val1”中的值“cast”,我正在寻找的是第一列、第二列和第三列中的所有不同值都被转换为对于某个电子邮件“用户”,列标题和行中的值将是该值的总和。 有一个数据透视表的东西,但我无法让它工作。 我将这些数据作为 mysql 中的表处理,但它在 csv 文件中可用,因此如果无法通过查询,python 将是一个可能的解决方案,并且在 sql 之后首选。

更新 在python中,是否可以将数据输出为:

+-------+--------+---------+------+----------+-----+--------+-------+
|       |     val1         |      val2       |     val3              |
+-------+--------+---------+------+----------+-----+--------+-------+
| email | cast   |little ja|core  | qar      |cam  | ja sa  | jaja   |
+-------+--------+---------+------+----------+-----+--------+--------|
|jal@h  |  55    |   2     | 44   |   244    | 1   | 200    | 12     |
|hal@b  |  900   |  513    | 101  |   146    |  2  |  733   | 833    |
|bam@t  |  1231  |   33    | 433  |   411    | 933 | 833    | 53     |
+-------+--------+--------+------+----------+-----+--------+---------

我对python不是很熟悉。

【问题讨论】:

【参考方案1】:

如果您使用 pandas,您可以在通过电子邮件将数据框分组后执行 value_counts,然后将其 unstack/pivot 转换为宽格式:

(df.set_index("email").stack().groupby(level=0).value_counts()
   .unstack(level=1).reset_index().fillna(0))


要获得更新的结果,您可以在stack 之后按电子邮件和val* 列进行分组:

(df.set_index("email").stack().groupby(level=[0, 1]).value_counts()
   .unstack(level=[1, 2]).fillna(0).sort_index(axis=1))

【讨论】:

它就像一个魅力!!!!每列的值变化很大,但很干净,谢谢【参考方案2】:

我会重建数据帧,然后使用 pd.value_counts 进行分组和取消堆叠

v = df.values
s = pd.Series(v[:, 1:].ravel(), v[:, 0].repeat(3))

s.groupby(level=0).value_counts().unstack(fill_value=0)

       cam  cast  core  ja sa  jaja  little ja  qar
bam@t    1     1     1      0     0          0    0
hal@b    0     0     0      1     0          1    1
jal@h    1     1     1      0     1          1    1

【讨论】:

感谢文件顺利通过,不胜感激【参考方案3】:

如果您知道列表,您可以使用group by 计算它:

SELECT email,
       sum(val1 = 'cast') as `cast`,
       sum(val1 = 'core') as `core`,
       sum(val1 = 'cam') as `cam`,
       . . .
FROM table1
GROUP BY email;

. . . 供您填写剩余的值。

【讨论】:

【参考方案4】:

您可以使用此查询从表中的值 val1-val3 动态生成 PREPARED 语句:

SELECT
    CONCAT( "SELECT email,\n",
        GROUP_CONCAT(
            CONCAT ("  SUM(IF('",val1,"' IN(val1,val2,val3),1,0)) AS '",val1,"'")
        SEPARATOR ',\n'),
        "\nFROM table1\nGROUP BY EMAIL\nORDER BY email") INTO @myquery
FROM (
    SELECT val1 FROM table1
    UNION SELECT val2 FROM table1
    UNION SELECT val3 FROM table1
) AS vals
ORDER BY val1;

-- ONLY TO VERIFY QUERY
SELECT @myquery;

PREPARE stmt FROM @myquery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

示例表

mysql> SELECT * FROM table1;
+----+-------+-----------+------+-------+
| id | email | val1      | val2 | val3  |
+----+-------+-----------+------+-------+
|  1 | jal@h | cast      | core | cam   |
|  2 | hal@b | little ja | qar  | ja sa |
|  3 | bam@t | cast      | core | cam   |
|  4 | jal@h | little ja | qar  | cast  |
+----+-------+-----------+------+-------+
4 rows in set (0,00 sec)

生成查询

mysql> SELECT
    ->     CONCAT( "SELECT email,\n",
    ->         GROUP_CONCAT(
    ->             CONCAT ("  SUM(IF('",val1,"' IN(val1,val2,val3),1,0)) AS '",val1,"'")
    ->         SEPARATOR ',\n'),
    ->         "\nFROM table1\nGROUP BY EMAIL\nORDER BY email") INTO @myquery
    -> FROM (
    ->     SELECT val1 FROM table1
    ->     UNION SELECT val2 FROM table1
    ->     UNION SELECT val3 FROM table1
    -> ) AS vals
    -> ORDER BY val1;
Query OK, 1 row affected (0,00 sec)

验证查询

mysql> -- ONLY TO VERIFY QUERY
mysql> SELECT @myquery;

SELECT email,
  SUM(IF('cast' IN(val1,val2,val3),1,0)) AS 'cast',
  SUM(IF('little ja' IN(val1,val2,val3),1,0)) AS 'little ja',
  SUM(IF('core' IN(val1,val2,val3),1,0)) AS 'core',
  SUM(IF('qar' IN(val1,val2,val3),1,0)) AS 'qar',
  SUM(IF('cam' IN(val1,val2,val3),1,0)) AS 'cam',
  SUM(IF('ja sa' IN(val1,val2,val3),1,0)) AS 'ja sa'
FROM table1
GROUP BY EMAIL
ORDER BY email

1 row in set (0,00 sec)

执行查询

mysql> PREPARE stmt FROM @myquery;
Query OK, 0 rows affected (0,00 sec)
Statement prepared

mysql> EXECUTE stmt;
+-------+------+-----------+------+------+------+-------+
| email | cast | little ja | core | qar  | cam  | ja sa |
+-------+------+-----------+------+------+------+-------+
| bam@t |    1 |         0 |    1 |    0 |    1 |     0 |
| hal@b |    0 |         1 |    0 |    1 |    0 |     1 |
| jal@h |    2 |         1 |    1 |    1 |    1 |     0 |
+-------+------+-----------+------+------+------+-------+
3 rows in set (0,00 sec)

mysql> DEALLOCATE PREPARE stmt;
Query OK, 0 rows affected (0,00 sec)

mysql>

【讨论】:

以上是关于将行值转换为列,并计算所有可能值 mysql 的重复次数的主要内容,如果未能解决你的问题,请参考以下文章

分组后将行值显示为列-Oracle

将行转换为列并计算总和

mysql 将行转置为列

将行值转换为列名

MySQL - 将行显示为列(尽可能简单)

不能从子查询将行转换为列