【问题标题】:Converting rows with too many values to columns将具有太多值的行转换为列
【发布时间】:2016-05-24 22:20:54
【问题描述】:

假设我有一个这样的数据集。

ID  Item
1   A
2   B
3   A
1   C
2   B
2   B
1   A
3   B

实际数据集有 50K 行和 8.5K 个不同的 Item 值。

现在我想将每个 Id 的行转换为列,以便我们计算每个用户的每个项目的值。如下所示

ID  A   B   C
1   2   0   1
2   0   3   0
3   1   1   0

现在如果我喜欢设置没有。项目值然后我可以硬编码它们以防聚合语句。

有点像

select ID, count(case when Item ='A' then 1 else Null end) A, 
count(case when Item='B' then 1 else Null end) B... and so on. 

但在这种情况下,我有 8.5K 唯一项。这将是太多的任务,如上面的 sql 中所做的那样。

我怎样才能做到这一点是 Sql 和 ii) Python。请记住,我有 50K 行和 8.5k 个唯一项,因此 python 循环可能会有点慢。

但我的第一个目标是在 sql 中执行此操作,因为这是 50K 的样本数据。当数据变大时,sql 仍然可以很好地保持它,但是我觉得 python 会变慢。在 python 中我也可以尝试一些代码。但是当数据超过 50K obs 时,python 也会变得很慢

请指教

不使用 Postgresql 并使用 HANA,因此特定于 Postgres 的功能可能不起作用。请建议通用的sql方式。

【问题讨论】:

  • 您正在寻找的是 MySQL 不支持的“Cross Tab”查询。它必须是代码(或存储过程),或类似于您建议的查询。但是该查询应该使用SUM,或者COUNT 中的ELSE 应该是ELSE NULL; COUNT 计数为 0。
  • 是的。但我不能使用我提议的那个。我在 Item 中有 8.5K 唯一值。不能硬编码 8.5K 次。那么它的8k行代码。我使用的是 HANA 而不是 Mysql。我正在寻找任何特定函数(如 Pivot 或 Crosstab)之外的通用 sql 查询,因为 PIVOT 和 CROSSTAB 不会在 HANA 中出现
  • 您是否需要以特定形式在某处(导出)显示该信息,或者您需要访问应用中的计数来计算某些内容?
  • 基本上我正在处理如上图 1 所示的数据集。我需要将其转换为 2,以便我可以使用 2 来进行我正在做的一些进一步的分析。数据必须采用 2 格式才能进行分析。所以这就是为什么我需要创建一个新的数据集来从 1 转换为 2。

标签: python mysql sql


【解决方案1】:

如果您确实想在 python 中执行此操作,您应该查看 pandas

df = pd.DataFrame({
    'ID': [1, 2, 3, 1, 2, 2, 1, 3],
    'Item': ['A', 'B', 'A', 'C', 'B', 'B' , 'A', 'B']
})

pd.crosstab(df['ID'], df['Item'])

输出:

Item A  B   C
ID          
1   2   0   1
2   0   3   0
3   1   1   0

【讨论】:

  • 谢谢。但我担心的是,当行和值大于 50K 和 8.5K 时,它可能会变慢。所以sql会更好。关于如何在 sql 中执行的任何想法?
  • 我试过了,还是不行。但是,我现在正尝试在 Python 中对其进行原型设计。为此,我将数据从 HANA 拉到 python。我使用了以下代码。拉动时它给了我一些 NULL 值。 HANA 中的原始表没有任何 NULL。不知道为什么? sql=""" select * from "Table A" """ df=psql.read_sql(sql,conn)
  • 恐怕我对HANA不熟悉。你用什么连接?如果您执行 cur = conn.cursor(); cur.execute('SELECT * FROM "Table A"'); cur.fetchmany(5) 之类的操作,您会得到什么
【解决方案2】:

对于 SQL 解决方案,如何使用 SQL 技术但编写脚本?不知道它会如何支撑,但如果你还没有尝试过,你可以试一试。 运行这样的东西来生成你需要的所有列的脚本:

select distinct 'sum(case when ITEM = ''' + ITEM + ''' then 1 else 0 end) ' + ITEM + ',' from YOUR_TABLE;

然后复制粘贴出来的结果:

select 
  ID,
  **<COPY AND PASTE RESULTS HERE>**
from TEST_DATA
group by ID;

【讨论】:

  • 我不确定该命令是否有效。您将 sum 语句放在引号内。我删除了引号并尝试了。错误。 SAP DBTech JDBC:[257]:sql 语法错误:“+ ITEM +”附近的语法不正确:第 1 列第 74 行(在 pos 74)
  • 试试这个:select distinct concat('sum(case when ITEM = ''', ITEM, ''' then 1 else 0 end) ', ITEM, ',') from YOUR_TABLE;
  • 请记住,这是生成脚本供您使用,而不是实际执行它。这就是 sum 语句在引号内的原因。您必须手动将结果复制并粘贴到第二个语句中(同时删除最后一个逗号)。这样您就不必为 8.5k 不同的物品输入箱子。
  • 没用。 SAP DBTech JDBC:[316]:函数调用中的参数数量错误:第 1 列第 17 行(在 pos 16)
  • 不确定是什么问题。在此处查看演示:rextester.com/WVGGSY40997
【解决方案3】:

这个查询可以生成你想要的查询:

SELECT CONCAT("SELECT ID"
    , GROUP_CONCAT(DISTINCT 
        CONCAT(", COUNT(CASE Item WHEN '", Item, "' THEN 1 ELSE NULL END) AS `", Item, "`")
        ORDER BY Item
        )
    , "FROM `theTable` "
    , "GROUP BY ID"
  ) AS theQuery
FROM `theTable`
;

....但我只知道GROUP_CONCAT 在 MySQL 中肯定存在,而在 MSSQL 中不存在;我不知道其他数据库系统。此外,在 MySQL 中,您需要通过在此查询之前使用类似

的语句来增加函数允许的最大长度
SET SESSION group_concat_max_len = 1000000;

...或更改服务器配置以使默认最大值更大。 ...其中“1000000”的长度足够大,不会截断生成的字符串。

如果查询太大以至于 group_concat 无论如何设置都无法适应它:您可以运行多个这样的查询,使用 WHERE 来减少处理的 Item 值,以生成更小的 ", COUNT(...), COUNT(" 列表;然后手动合并这些结果。

当然,即使这样生成了想要的查询,我也不肯定 MySQL 会接受那么长的查询。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 2018-02-04
    • 1970-01-01
    相关资源
    最近更新 更多