【问题标题】:flask-sqlalchemy query for returning newest and using distinct columns用于返回最新并使用不同列的 flask-sqlalchemy 查询
【发布时间】:2021-03-11 20:49:56
【问题描述】:

我真的很难在 flask-sqlalchemy 中编写我想要的正确 postgres 查询。

下面是我的数据的示例表。我正在尝试返回 xxx 和 yyy 以获取每个唯一 name 的最新(最新时间戳)。

理想情况下,对于下面的数据,我希望我的查询返回底部的 4 个条目。

+------------+-------+-----+--------------------------+
|    name    |  xxx  | yyy |           time           | ... (other columns)
+------------+-------+-----+--------------------------+
| aaa        |   2   |  12 | 2021-03-11 20:27:13+00   |
| bbbb       |   9   |  13 | 2021-03-11 20:27:13+00   |
| cccc       |   2   |  16 | 2021-03-11 20:27:13+00   |
| dddd       |   10  |  26 | 2021-03-11 20:27:13+00   |
| aaa        |   4   |  13 | 2021-03-11 20:27:23+00   |
| bbbb       |   8   |  12 | 2021-03-11 20:27:23+00   |
| cccc       |   1   |  15 | 2021-03-11 20:27:23+00   |
| dddd       |   12  |  26 | 2021-03-11 20:27:23+00   |
| aaa        |   3   |  12 | 2021-03-11 20:27:33+00   |
| bbbb       |   6   |  11 | 2021-03-11 20:27:33+00   |
| cccc       |   1   |  17 | 2021-03-11 20:27:33+00   |
| dddd       |   13  |  23 | 2021-03-11 20:27:33+00   |
+------------+-------+-----|--------------------------+

我最基本的返回单个条目的最新看起来像:

single_query = MyModel \
    .query \
    .filter_by(name = 'aaaa) \
    .order_by(desc(MyModel.time)) \
    .first()

使用我的模型,我尝试通过如下查询(基于其他一些 SO 答案)获得预期结果:

full_query = MyModel \
    .query \
    .with_entities(MyModel.name, MyModel.time, MyModel.xxx) \
    .distinct(MyMmodel.name) \
    .all()

这让我大部分时间到达那里,但它返回随机条目(似乎至少)。我以为我可以很容易地添加一个order_by(desc(MyModel.time)),但我不能让它与上面的查询一起工作。

关于如何让它工作的任何建议或一些让我朝着正确方向前进的建议?我一直在挠头一段时间。 :)

我进行了大量搜索,但不知道如何将这样的答案 (SQLalchemy distinct, order_by different column) 扩展到我的模型查询。


更新

如果我想一次查询两个表,例如sample_table_1 和sample_table_2 通过MyModel 和MyModel2,我如何将postgres 转换为flask-sqlalchemy?

实现我想要的原始查询如下: 我能够以@Oluwafemi Sule 的有用答案为基础。我可以扩展这个或解决方案查询以满足我的需要:)

SELECT
  m.name,
  m.xxx,
  m.yyy
  n.xxx,
  n.yyy
FROM (
  SELECT
    name,
    xxx,              
    yyy,
    ROW_NUMBER() OVER(PARTITION BY container_name ORDER BY time DESC) AS rn       
  FROM                          
    sample_table_1
) m, (
  SELECT
    name,
    xxx,
    yyy,
    ROW_NUMBER() OVER(PARTITION BY container_name ORDER BY time DESC) AS rn 
  FROM
    sample_table_2
) n
WHERE m.container_name = n.container_name and m.rn = 1 and n.rn = 1;

【问题讨论】:

    标签: python postgresql sqlalchemy flask-sqlalchemy


    【解决方案1】:

    获取预期结果的 SQL 查询如下:

    SELECT 
      name
      ,xxx
      ,yyy
      ,time 
    FROM
     ( 
       SELECT 
         name
         ,xxx
         ,yyy
         ,time
         -- Number rows after partitioning by name and reverse chronological ordering
         ,ROW_NUMBER () OVER (PARTITION BY name ORDER BY time DESC) AS rn
      FROM sample_table
    ) subquery
    WHERE rn = 1; 
    

    现在,编写 SQLAlchemy 查询如下:

    from sqlalchemy import func
    
    subquery = (
        MyModel
        .query
        .with_entities(
            MyModel.name, 
            MyModel.time, 
            MyModel.xxx, 
            MyModel.yyy,
            func.row_number().over(
                partition_by=MyModel.name,
                order_by=MyModel.time.desc()
            ).label("rn")
        )
    )
    full_query = (
        MyModel.query.with_entities(
            subquery.c.name,
            subquery.c.time,
            subquery.c.xxx,
            subquery.c.yyy
        )
        .select_from(subquery)
        .filter(subquery.c.rn == 1)
        .all()
    )
    

    【讨论】:

    • 优秀的答案!我认为您只是在子查询定义中缺少附加的.subquery()。我现在正试图能够将两个表的结果作为一个查询返回。所以我有两个模型,MyModel 和 MyModel2。我已经得到了一个 postgres 查询(参见上面的更新),但是在如何转换为 flask-sqlalchemy 时遇到了麻烦!有什么建议吗?
    【解决方案2】:

    您可以通过为每列选择不同的 first_value 来获得所需的结果,按名称分区并按时间排序

    使用 sqlalchemy.core 语言

    import sqlalchemy as sa
    from sqlalchemy import func
    
    stmt = sa.select([
       func.first_value(c)
         .over(partition_by=MyModel.name,
               order_by=MyModel.time.desc())
         .label(c.name)
       for c in MyModel.__table__.c
       ]).distinct()
    

    这会生成类似的 sql:

    select distinct 
    first_value(my_model.name) OVER (PARTITION BY name ORDER BY time DESC) AS name, ...
    from my_model
    

    【讨论】:

      猜你喜欢
      • 2013-04-12
      • 1970-01-01
      • 2015-10-18
      • 2020-02-17
      • 1970-01-01
      • 2022-10-18
      • 2021-12-01
      • 2020-09-19
      • 2016-05-07
      相关资源
      最近更新 更多