0

want to get last 2 name in my table for example

id    name    price
1     name1   100
2     name2   120
3     name3   100
4     name3   150
5     name3   152

i want result become

name
name3
name2

already searched similar questions here but find no answer in SQLalchemy

my try

orders = db.session.query(Table.name).filter(SomeFilter).order_by(Table.id.desc()).group_by(
        Table.name).all() 

problem is group_by and order_by in same time have no issue with limit

EDIT2

result = session.query(test).order_by(test.i.desc()).with_entities(test.j).distinct(test.j).limit(2)

get error in postgress too

Nozar Safari
  • 505
  • 4
  • 17
  • use `limit()`, see: [Sqlalchemy get last X rows in order](https://stackoverflow.com/questions/12345015/sqlalchemy-get-last-x-rows-in-order) – Luuk Dec 04 '21 at 10:04
  • want ```group_by``` and ```limit``` if use ```group_by``` ```limit``` not work correctly – Nozar Safari Dec 04 '21 at 10:07
  • problem is ```order by``` after ```group by``` will sort on aliphatic order i want to sort on updated time – Nozar Safari Dec 04 '21 at 13:38

1 Answers1

2

OK, I am (very) new to sqlalchemy (so do not mention the 'lot of' imports at the start of this code ), but see my code:


import sqlalchemy

from sqlalchemy import create_engine, Column, String, Integer, MetaData, Table
from sqlalchemy import text
from sqlalchemy.orm import Session
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine("sqlite+pysqlite:///test.db", echo=True)

Base = declarative_base()
metadata = MetaData(engine)
class test(Base):
    __tablename__ = 'test'
    i = Column(Integer,primary_key=True)
    j = Column(Integer)

with Session(engine) as session:
    session.execute("""CREATE TABLE test(i int primary key,j int)""")
    session.execute("""DELETE FROM test""")
    t1 = test(i=1, j=1)
    session.add(t1)
    session.add(test(i=2,j=5))
    session.add(test(i=3,j=5))
    session.add(test(i=4,j=2))
    session.add(test(i=5,j=2))
    session.add(test(i=6,j=3))
    session.add(test(i=7,j=3))
    session.add(test(i=8,j=3))

    session.commit()
    result = session.query(test).group_by(test.j).order_by(test.j.desc()).limit(2)
    for row in result:
          print(f"I: {row.i}  J: {row.j}")

BTW: The DELETE FROM... is only needed on second run, when I comment the line with CREATE TABLE....

the output is:

I: 6  J: 3
I: 4  J: 2

EDIT: The items should be sorted on i desc. To get that done you can use the following code:

(NOTE: j=1 is changed to j=5, to get the correct result)

    subquery = session.query(test).order_by(test.i.desc()).with_entities(test.j).subquery()
    result = session.query(subquery).distinct().limit(2)
    for row in result:
          print(f"J: {row.j}")

which, with my sample data, returns:

J: 3
J: 2

EDIT2: Better result always arise after posting the code here....

It can be done without subquery:

result = session.query(test).order_by(test.i.desc()).with_entities(test.j).distinct(test.j).limit(2)

EDIT3: It appears the postgresql is giving an error (see comments).

the following changes are needed to solve this (with help from PG::Error: SELECT DISTINCT, ORDER BY expressions must appear in select list:

  • add from sqlalchemy import func
  • change create engine(sqlite... to create_engine("postgresql://user:password@localhost/dbname", echo=True,)
  • finally the selection looks like:
    result = session.query(test).order_by(func.min(test.i).desc()).with_entities(test.j).group_by(test.j).limit(2)
    for row in result:
          print(f"J: {row.j}")

see also (Postgres14): DBFIDDLE

see also (SQLite): DBFIDDLE

or the DBFIDDLE's side-by-side: https://dbfiddle.uk/?rdbms=sqlite_3.27&rdbms2=postgres_14&fiddle=afd9687da44ec2ce2c66d9e08ee38b18

Luuk
  • 12,245
  • 5
  • 22
  • 33
  • this will sort on aliphatic order of name, i want to sort before ```group by``` or sort according id ```desc``` in other word sort on ```id``` then group by ```name``` – Nozar Safari Dec 04 '21 at 13:40
  • Sorry my English fails to understand what you tried to say (I am not a native English speaker) – Luuk Dec 04 '21 at 13:43
  • change ```j=1``` in your code to ```j=5``` and check result pls, result must be same but code will return 5 and 3 – Nozar Safari Dec 04 '21 at 13:45
  • OK, so you seem to want the result of the last SQL statement in this [DBFIDDLE](https://dbfiddle.uk/?rdbms=sqlite_3.27&fiddle=6f25f9135afacb5bc8efb069ba2ef7db) – Luuk Dec 04 '21 at 14:45
  • Added an EDIT, and an EDIT2. – Luuk Dec 04 '21 at 15:12
  • still have issue in postgress ```SELECT DISTINCT ON expressions must match initial ORDER BY expressions``` – Nozar Safari Dec 04 '21 at 20:13
  • Added EDIT3. P.S. this question shows that it is **important** to include all the details in the question. ( I know it is hard to share details that are important, but do not look important to the writer of the question.... ) – Luuk Dec 05 '21 at 10:14