SQLite:转置 GROUP BY 的结果并用名称填充 ID

SQLite: Transposing results of a GROUP BY and filling in IDs with names

我的问题比较具体,如果你有更好的标题请推荐一个。此外,格式很糟糕 - 不知道如何组合列表和代码块。

我有一个 SQLite3 数据库,其中包含以下(的相关部分).schema:

CREATE TABLE users (id INTEGER PRIMARY KEY NOT NULL, user TEXT UNIQUE);
CREATE TABLE locations (id INTEGER PRIMARY KEY NOT NULL, name TEXT UNIQUE);
CREATE TABLE purchases (location_id INTEGER, user_id INTEGER);
CREATE TABLE sales (location_id integer, user_id INTEGER);

purchases 有大约 450 万个条目,users 大约 300k,sales 大约 100k,locations 大约 250 - 只是为了衡量数据量。

我想要的用途是生成一个 JSON object 以传递给另一个应用程序,通过执行以下操作在数量上非常压缩:

-通过 location_id、user_id 将购买和销售分组为一个共同的 table - IOW,获取每个用户每个位置的 "actions" 数量。我能做到,结果类似于

loc  | usid  | loccount
-----------------------
1    | 1246  | 123
1    | 2345  | 1
13   | 1246  | 46
13   | 8732  | 4
27   | 2345  | 41

(至少看起来不错,这样的体积总是很难分辨;查询:

select location_id,user_id,count(location_id) from
  (select location_id,user_id from purchases
     union all
   select location_id,user_id from sales)
group by location_id,user_id order by user_id`

)

-然后,转置那个巨人 table 这样我会得到:

usid | loc1 | loc13 | loc27
---------------------------
1246 | 123  | 46    | 0
2345 | 1    | 0     | 41
8732 | 0    | 4     | 0

我做不到,这是我对这个问题的绝对关键点。我尝试了一些我在网上找到的东西,尤其是在这里,但我刚刚开始使用 SQLite 并且不了解很多查询。

-最后,将table翻译成纯文本,以便写入JSON:

user | AAAA | BBBBB | CCCCC
---------------------------
zeta | 123  | 46    | 0
beta | 1    | 0     | 41
iota | 0    | 4     | 0

可能 可以做很多实验和内部连接,尽管我总是不确定处理此类数据量的最佳方法是什么,因此我不介意一个指针。

整个事情都写在Python的sqlite3接口中,如果重要的话。最后,我希望有一些东西我可以为每个用户做一个 "for" 循环以生成 JSON,这当然会非常简单。如果查询需要很长时间(<10 分钟就好了)也没关系,它只是每天 运行 两次作为一种备份。我只有一个很小的 ​​VPS 可用,但仅限于单核,性能与我相当强大的台式机一样好。 (i5-3570k 运行宁 Debian。)

table headers 只是示例,因为我不太确定我是否可以为它们使用整数(如果可以,我没有发现语法),只要我是以某种方式能够在 table 位置查找数字部分我很好。将用户 ID 转换为名称也是如此。列数是事先已知的——它们毕竟只是 INTEGER PRIMARY KEY,我从其他操作中得到了 list() 个。行数可以相当快地确定,大约 3 秒,如果需要的话。

考虑使用子查询来实现您想要的转置输出:

SELECT DISTINCT m.usid,

   IFNULL((SELECT t1.loccount FROM tablename t1 
         WHERE t1.usid = m.usid AND t1.loc=1),0) AS Loc1,
   IFNULL((SELECT t2.loccount FROM tablename t2 
         WHERE t2.usid = m.usid AND t2.loc=13),0) AS Loc13,
   IFNULL((SELECT t3.loccount FROM tablename t3 
         WHERE t3.usid = m.usid AND t3.loc=27),0) AS Loc27

FROM tablename As m

或者,您可以使用嵌套的 IF 语句(或者在使用 CASE/WHEN 的 SQLite 的情况下)派生 table:

SELECT temp.usid, Max(temp.loc1) As Loc1, 
       Max(temp.loc13) As Loc13, Max(temp.loc27) As Loc27
FROM    
   (SELECT tablename.usid, 
      CASE WHEN loc=1 THEN loccount ELSE 0 As Loc1 END,  
      CASE WHEN loc=13 THEN loccount ELSE 0 As Loc13 END, 
      CASE WHEN loc=27 THEN loccount ELSE 0 As Loc27 END
    FROM tablename) AS temp    
GROUP BY temp.usid