按日期排序,而按另一列分组匹配项

时间:2019-01-12 10:51:22

标签: sql sqlite group-by sql-order-by

我有这个查询

SELECT *, COUNT(app.id) AS totalApps FROM users JOIN app ON app.id = users.id
  GROUP BY app.id ORDER BY app.time DESC LIMIT ?

应该从相关表中另一列(时间)排序的“用户”获得所有结果(应用程序表中的ID引用用户表中的ID)。

我的问题是,分组是在按日期排序之前完成的,所以得到的结果非常旧。但是我需要进行分组才能获得不同的用户,因为每个用户可以有多个“应用程序” ...是否有其他方法可以实现这一目标?


表用户:

id TEXT PRIMARY KEY

表格应用程序:

id TEXT
time DATETIME
FOREIGN KEY(id) REFERENCES users(id)

在我的SELECT查询中,我想获取一个由app.time列排序的用户列表。但是因为一个用户可以关联多个应用程序记录,所以我可以得到重复的用户,这就是为什么我使用GROUP BY的原因。但是后来订单搞砸了

5 个答案:

答案 0 :(得分:1)

由于您需要每个组中的最新日期,因此您可以$router->get('/end', ['as'=>'name_here', function()]);

MAX

答案 1 :(得分:1)

您可以使用窗口COUNT

SELECT *, COUNT(app.id) OVER(PARTITION BY app.id) AS totalApps 
FROM users 
JOIN app 
  ON app.id = users.id
ORDER BY app.time DESC
LIMIT ?

答案 2 :(得分:1)

潜在的问题是SELECT是一个聚合查询,因为它包含GROUP BY子句:-

  

简单的SELECT语句有两种类型-聚合和   非汇总查询。一个简单的SELECT语句是一个聚合查询   如果包含GROUP BY子句或一个或多个聚合   功能在结果集中。

SQL As Understood By SQLite - SELECT

因此该组列的值将是该组列的任意值(我怀疑首先是根据扫描/搜索,因此是较低的值):-

  

如果SELECT语句是不带GROUP BY的聚合查询   子句,然后对结果集中的每个聚合表达式求值   一次遍及整个数据集。中的每个非聚合表达式   结果集对任意选择的行评估一次   数据集。每个行都使用相同的任意选择的行   非聚合表达式。或者,如果数据集包含零行,则   每个非集合表达式都针对包含   完全是NULL值。

因此,简而言之,当它是聚合查询时,您不能依赖不属于组/聚合的列值。

因此必须使用聚合表达式(例如max(app.time))检索所需的值。但是,您不能按此值进行排序(不确定确切的原因,因为它可能在效率方面是固有的)

如何

您可以做的是使用查询建立CTE,然后在不涉及聚合的情况下进行排序。

请考虑以下内容,我认为这类似于您的问题:-

DROP TABLE IF EXISTS users;
DROP TABLE If EXISTS app;

CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, username TEXT);
INSERT INTO users (username) VALUES ('a'),('b'),('c'),('d');

CREATE TABLE app (the_id INTEGER PRIMARY KEY, id INTEGER, appname TEXT, time TEXT);
INSERT INTO app (id,appname,time) VALUES
    (4,'app9',721),(4,'app10',7654),(4,'app11',11),
        (3,'app1',1000),(3,'app2',7),
        (2,'app3',10),(2,'app4',101),(2,'app5',1),
        (1,'app6',15),(1,'app7',7),(1,'app8',212),
        (4,'app9',721),(4,'app10',7654),(4,'app11',11),
        (3,'app1',1000),(3,'app2',7),
        (2,'app3',10),(2,'app4',101),(2,'app5',1),
        (1,'app6',15),(1,'app7',7),(1,'app8',212)
    ;
    SELECT * FROM users;
    SELECT * FROM app;

    SELECT username 
      ,count(app.id) 
      , max(app.time) AS latest_time
        , min(app.time) AS earliest_time
    FROM users JOIN app ON users.id = app.id 
    GROUP BY users.id
    ORDER BY max(app.time)
    ;

结果为:-

enter image description here

尽管每个组的最新时间都已提取,但最终结果却没有按照您的想象进行排序。

将其包装到CTE中可以解决例如:-

WITH cte1 AS 
(
    SELECT username 
        ,count(app.id) 
        , max(app.time) AS latest_time
        , min(app.time) AS earliest_time
    FROM users JOIN app ON users.id = app.id 
    GROUP BY users.id
)
SELECT * FROM cte1 ORDER BY cast(latest_time AS INTEGER) DESC;

现在:-

enter image description here

  • 为方便起见,请注意使用简单的整数代替了实时数。

答案 3 :(得分:0)

也许您可以使用?

SELECT DISTINCT

在此处了解更多信息:https://www.w3schools.com/sql/sql_distinct.asp

答案 4 :(得分:0)

尝试按ID和时间分组,然后按时间排序。

select ... 
group by app.id desc, app.time

我认为id在应用表中是唯一的。 以及您如何分配ID?也许您有足够的通过id desc

进行订购