SQLite:仅返回每组中的前 2 个结果
Posted
技术标签:
【中文标题】SQLite:仅返回每组中的前 2 个结果【英文标题】:SQLite: return only top 2 results within each group 【发布时间】:2018-05-16 03:18:02 【问题描述】:我检查了类似问题的其他解决方案,但 sqlite 不支持 row_number()
和 rank()
函数,或者没有涉及连接多个表、按多列分组并仅返回的示例每个组同时获得前 N 个结果。
这是我运行的代码
db = sqlite3.connect('mydb')
cursor = db.cursor()
cursor.execute(
'''
CREATE TABLE orders(
id INTEGER PRIMARY KEY, product_id INTEGER,
client_id INTEGER
)
'''
)
cursor.execute(
'''
CREATE TABLE clients(
id INTEGER PRIMARY KEY, gender TEXT,
city TEXT
)
'''
)
cursor.execute(
'''
CREATE TABLE products(
id INTEGER PRIMARY KEY, category_name TEXT
)
'''
)
orders = [
(9, 6), (3, 10), (8, 6), (4, 8),
(5, 6), (7, 4), (9, 2), (10, 8),
(4, 6), (3, 1), (10, 2), (9, 8),
(9, 7), (4, 9), (7, 10), (2, 7),
(4, 7), (6, 2), (6, 2), (9, 3),
(10, 6), (4, 4), (2, 6), (3, 8),
(9, 2), (1, 9), (3, 9), (9, 4),
(5, 5), (7, 1), (8, 7), (7, 8),
(6, 3), (9, 6), (8, 3), (7, 1),
(10, 5), (7, 10), (8, 1), (7, 9),
(4, 4), (3, 8), (5, 2), (5, 8),
(6, 10), (9, 7), (2, 2), (4, 10),
(5, 10), (3, 9)
]
clients = [
('Male', 'NY'),
('Female', 'NY'),
('Male', 'London'),
('Male', 'London'),
('Male', 'NY'),
('Female', 'NY'),
('Female', 'London'),
('Male', 'London'),
('Male', 'NY'),
('Female', 'London')
]
products = [
('Kitchen', ),
('Sport', ),
('Furniture', ),
('Furniture', ),
('Furniture', ),
('Sport', ),
('Sport', ),
('Kitchen', ),
('Kitchen', ),
('Kitchen', )
]
cursor.executemany("INSERT INTO orders(product_id, client_id) VALUES(?,?)", orders)
cursor.executemany("INSERT INTO clients(gender, city) VALUES(?,?)", clients)
cursor.executemany("INSERT INTO products(category_name) VALUES(?)", (products))
db.commit()
cursor.execute(
'''
SELECT
category_name,
city, gender,
product_id, COUNT(product_id)
FROM orders
LEFT JOIN products ON product_id = products.id
LEFT JOIN clients ON client_id = clients.id
GROUP BY product_id, category_name, city, gender
ORDER BY category_name, city, gender, COUNT(product_id) DESC
'''
)
print('''category_name, city, gender, product_id, COUNT(product_id)''')
all_rows = cursor.fetchall()
for a, b, c, d, e in all_rows:
print(a, b, c, d, e)
db.close()
现在的问题是如何在单个查询中获得这样的输出?我不需要用红线交叉的行,因为我只需要前 2 个。
【问题讨论】:
【参考方案1】:这可以通过使用 WITH
将现有查询嵌入到 CTE 中来实现,然后在 WHERE ... IN
子查询中使用它。子查询从 CTE 中选择与 category_name、城市和性别匹配的 LIMIT 2
产品 ID,按产品计数排序。
WITH order_groups AS (
SELECT
category_name,
city, gender,
product_id,
COUNT(product_id) AS product_count
FROM orders OO
LEFT JOIN products ON product_id = products.id
LEFT JOIN clients ON client_id = clients.id
GROUP BY product_id, category_name, city, gender
ORDER BY category_name, city, gender, COUNT(product_id) DESC
)
SELECT * FROM order_groups OG_outer
WHERE OG_outer.product_id IN (
SELECT product_id
FROM order_groups OG_inner
WHERE
OG_outer.category_name = OG_inner.category_name AND
OG_outer.city = OG_inner.city AND
OG_outer.gender = OG_inner.gender
ORDER BY OG_inner.product_count DESC LIMIT 2
)
ORDER BY category_name, city, gender, product_count DESC
这会根据要求输出以下行:
Furniture|London|Female|4|2
Furniture|London|Female|3|1
Furniture|London|Male|4|3
Furniture|London|Male|3|2
Furniture|NY|Female|5|2
Furniture|NY|Female|4|1
Furniture|NY|Male|3|3
Furniture|NY|Male|4|1
Kitchen|London|Female|9|2
Kitchen|London|Female|8|1
Kitchen|London|Male|9|3
Kitchen|London|Male|8|1
Kitchen|NY|Female|9|4
Kitchen|NY|Female|10|2
Kitchen|NY|Male|1|1
Kitchen|NY|Male|8|1
Sport|London|Female|7|2
Sport|London|Female|2|1
Sport|London|Male|7|2
Sport|London|Male|6|1
Sport|NY|Female|2|2
Sport|NY|Female|6|2
Sport|NY|Male|7|3
【讨论】:
以上是关于SQLite:仅返回每组中的前 2 个结果的主要内容,如果未能解决你的问题,请参考以下文章